Topological Fluctuation Graph Layer / topological_fluctuation.py
Failed on benchmark
1import json
2import numpy as np
3
4SX=np.array([[0,1],[1,0]],complex)
5SY=np.array([[0,-1j],[1j,0]],complex)
6SZ=np.array([[1,0],[0,-1]],complex)
7I2=np.eye(2,dtype=complex)
8
9def H(kx,ky,m,q=1.):
10 return q*np.sin(kx)*SX + q*np.sin(ky)*SY + (m+np.cos(kx)+np.cos(ky))*SZ
11
12def drift(kx,ky,m,gamma,q=1.):
13 return -gamma*I2-1j*H(kx,ky,m,q)
14
15def spectrum(kx,ky,m,gamma,omega=0.8,noise=1.,q=1.):
16 A=drift(kx,ky,m,gamma,q)
17 G=np.linalg.inv(-1j*omega*I2-A)
18 return G@(noise*I2)@G.conj().T
19
20def link(a,b):
21 z=np.vdot(a,b)
22 return z/(abs(z)+1e-30)
23
24def fukui_chern(m,gamma=.7,omega=.8,n=41,band=0):
25 us=np.empty((n,n,2),complex)
26 for ix in range(n):
27 for iy in range(n):
28 w,v=np.linalg.eigh(spectrum(2*np.pi*ix/n,2*np.pi*iy/n,m,gamma,omega))
29 us[ix,iy]=v[:,::-1][:,band]
30 total=0.
31 for ix in range(n):
32 for iy in range(n):
33 u=us[ix,iy]; ux=us[(ix+1)%n,iy]; uy=us[ix,(iy+1)%n]
34 uxy=us[(ix+1)%n,(iy+1)%n]
35 plaquette=link(u,ux)*link(ux,uxy)*link(uxy,uy)*link(uy,u)
36 total += np.angle(plaquette)
37 return total/(2*np.pi)
38
39def min_gap(m,gamma=.7,omega=.8,n=81,noise=1.):
40 gaps=[]
41 for kx in np.linspace(-np.pi,np.pi,n,endpoint=False):
42 for ky in np.linspace(-np.pi,np.pi,n,endpoint=False):
43 w=np.linalg.eigvalsh(spectrum(kx,ky,m,gamma,omega,noise))
44 gaps.append(w[1]-w[0])
45 return float(np.min(gaps))
46
47def max_h2(m,n=81):
48 return max(np.linalg.eigvalsh(H(x,y,m)).max()**2 for x in np.linspace(-np.pi,np.pi,n,endpoint=False) for y in np.linspace(-np.pi,np.pi,n,endpoint=False))
49
50def euler_radius(dt,m,gamma,n=41):
51 r=0.
52 for x in np.linspace(-np.pi,np.pi,n,endpoint=False):
53 for y in np.linspace(-np.pi,np.pi,n,endpoint=False):
54 ev=np.linalg.eigvals(I2+dt*drift(x,y,m,gamma))
55 r=max(r,float(np.max(np.abs(ev))))
56 return r
57
58def strip_edge(m,gamma=.18,nx=40,ny=20,q=1.):
59 best=[]
60 chi=q
61 for kx in 2*np.pi*np.arange(nx)/nx:
62 M=np.zeros((2*ny,2*ny),complex)
63 for y in range(ny):
64 M[2*y:2*y+2,2*y:2*y+2]=(m+np.cos(kx))*SZ+chi*np.sin(kx)*SX
65 if y+1<ny:
66 T=(-1j*chi*SY+SZ)/2
67 M[2*y:2*y+2,2*(y+1):2*(y+1)+2]=T
68 M[2*(y+1):2*(y+1)+2,2*y:2*y+2]=T.conj().T
69 w,v=np.linalg.eigh(M)
70 for j,e in enumerate(w):
71 if abs(e)<0.35:
72 p=np.sum(abs(v[:,j].reshape(ny,2))**2,axis=1)
73 edge=(p[0]+p[1]+p[-1]+p[-2])/(p.sum()+1e-15)
74 ipr=float(np.sum(p*p))
75 best.append((edge,ipr,float(e)))
76 return max(best) if best else (0.,0.,999.)
77
78def main():
79 np.random.seed(0); gamma=.7; omega=.8
80 lam=max_h2(-1.); dtcrit=2*gamma/(gamma*gamma+lam)
81 dts=[.8*dtcrit,.99*dtcrit,1.01*dtcrit,1.2*dtcrit]
82 stability=[(dt,euler_radius(dt,-1.,gamma)) for dt in dts]
83 masses=[-2.5,-1.5,-.5,.5,1.5,2.5]
84 phase=[(m,round(fukui_chern(m,gamma,omega,n=31)),min_gap(m,gamma,omega,n=51)) for m in masses]
85 near=[(m,round(fukui_chern(m,gamma,omega,n=31),3),min_gap(m,gamma,omega,n=61)) for m in [-.2,-.1,-.05,.05,.1,.2]]
86 edge_top=strip_edge(-1.,q=1.); edge_triv=strip_edge(-1.,q=0.)
87 chirality=[(q,strip_edge(-1.,nx=32,ny=16,q=q)[:2]) for q in [0.,.1,.25,.5,1.]]
88 exact_gap=[(m,min_gap(m,gamma,omega,n=81)) for m in [-2.,0.,2.]]
89 out={'predictions':{
90 'stability_bound':{'predicted_dt_critical':dtcrit,'observed_dt_radius_1_crossing':stability,'pass': bool(all((r<1)==(dt<dtcrit) for dt,r in stability))},
91 'chern_gap_transition':{'predicted_boundaries':[-2,0,2],'phase_sweep':phase,'near_m0':near,'exact_boundary_gaps':exact_gap,'pass': bool(abs(phase[1][1])==1 and abs(phase[-2][1])==1 and min(x[2] for x in near)<max(x[2] for x in phase))},
92 'boundary_localization':{'topological_m_minus1_edge_ratio_ipr':edge_top,'deterministic_nonchiral_q0_baseline':edge_triv,'chirality_sweep':chirality,'pass':edge_top[0]>edge_triv[0]*2 and edge_top[1]>edge_triv[1]*1.3}
93 },'parameters':{'gamma':gamma,'omega':omega,'grid':31}}
94 print(json.dumps(out,indent=2))
95if __name__=='__main__': main()