def get_obs_ops(self): obs_ops = dict() s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) obs_ops["sz"] = s2.SZ() obs_ops["sp"] = s2.SP() obs_ops["sm"] = s2.SM() return obs_ops
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() rot_op = s2.BP_rot() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SS = SS.contiguous() SS_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, SS, rot_op) h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', SS, id2) h2x2_nn= h2x2_SS + h2x2_SS.permute(2,3,0,1,6,7,4,5) + h2x2_SS.permute(0,2,1,3,4,6,5,7)\ + h2x2_SS.permute(2,0,3,1,6,4,7,5) h2x2_nnn = h2x2_SS.permute(0, 3, 2, 1, 4, 7, 6, 5) + h2x2_SS.permute( 2, 0, 1, 3, 6, 4, 5, 7) h2x2_nn = h2x2_nn.contiguous() h2x2_nnn = h2x2_nnn.contiguous() # sublattice rotation for single-site bipartite (BP) ansatz h2x2_nn_rot= torch.einsum('irtlaxyd,jr,kt,xb,yc->ijklabcd',\ h2x2_nn,rot_op,rot_op,rot_op,rot_op) h2x2_nnn_rot= torch.einsum('irtlaxyd,jr,kt,xb,yc->ijklabcd',\ h2x2_nnn,rot_op,rot_op,rot_op,rot_op) h2x2_nn_rot = h2x2_nn_rot.contiguous() h2x2_nnn_rot = h2x2_nnn_rot.contiguous() return SS, SS_rot, h2x2_nn, h2x2_nnn, h2x2_nn_rot, h2x2_nnn_rot
def build_gate(tau=1.0, H=j1j2.J1J2_C4V_BIPARTITE(j1=args.j1, j2=args.j2)): """Part of j1j2.py code. H is a class with j1=1.0 and j2=0 by default. Simple pi/2 rotation of the gate gives the Hamiltonian on another bond.""" s2 = su2.SU2(H.phys_dim, dtype=H.dtype, device=H.device) expr_kron = 'ij,ab->iajb' # Spin-spin operator # s1| |s2 # | | # [ S.S ] # | | # s1'| |s2' SS = torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SS = SS.view(4, 4).contiguous() # Diagonalization of SS and creation of Hamiltonian Ha eig_va, eig_vec = np.linalg.eigh(SS) eig_va = np.exp(-tau / 2 * args.j1 * eig_va) U = torch.tensor(eig_vec) D = torch.diag(torch.tensor(eig_va)) # Ha = U D U^{\dagger} Ga = torch.einsum('ij,jk,lk->il', U, D, U) Ga = Ga.view(2, 2, 2, 2).contiguous() return Ga
def get_h(self): pd = self.phys_dim irrep = su2.SU2(pd, dtype=self.dtype, device=self.device) # identity operator on two spin-S spins idp = torch.eye(pd**2, dtype=self.dtype, device=self.device) idp = idp.view(pd, pd, pd, pd).contiguous() SS = irrep.SS() SS = SS.view(pd**2, pd**2) h2 = self.j1 * SS + self.k1 * SS @ SS # Reshape back into rank-4 tensor for later use with reduced density matrices h2 = h2.view(pd, pd, pd, pd).contiguous() h2x2_h2 = torch.einsum('ijab,klcd->ijklabcd', h2, idp) # Create operators acting on four spins-S on plaquette. These are useful # for computing energy by different rearragnement of Hamiltonian terms # # NN-terms along horizontal bonds of plaquette hp_h = h2x2_h2 + h2x2_h2.permute(2, 3, 0, 1, 6, 7, 4, 5) # NN-terms along vertical bonds of plaquette hp_v = h2x2_h2.permute(0, 2, 1, 3, 4, 6, 5, 7) + h2x2_h2.permute( 2, 0, 3, 1, 6, 4, 7, 5) # All NN-terms within plaquette hp = hp_h + hp_v return h2, hp_h, hp_v, hp
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) expr_kron = 'ij,ab->iajb' SS = torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) rot_op = s2.BP_rot() SS_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, SS, rot_op) return SS, SS_rot
def get_h(self): # from "bra" tuple of indices return corresponing bra-ket pair of indices # 0 -> 0;1; 1,0 -> 1,0;3,2; ... def bk(*bras): kets = [b + len(bras) for b in bras] return tuple(list(bras) + kets) s2 = su2.SU2(2, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() id3 = torch.eye(8, dtype=self.dtype, device=self.device) id3 = id3.view(2, 2, 2, 2, 2, 2).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SSp = SS - 0.25 * id2 SSid2 = torch.einsum('ijab,klcd->ijklabcd', SS, id2) SSpSSp = torch.einsum('ijab,klcd->ijklabcd', SSp, SSp) SSpSSp = SSpSSp + SSpSSp.permute(bk(0, 2, 1, 3)) # on-site term h1= self.j1*(SSid2 +SSid2.permute(bk(2,3,0,1)) +SSid2.permute(bk(0,2,1,3))\ +SSid2.permute(bk(2,0,3,1))) - self.q*SSpSSp h1 = h1.view(self.phys_dim, self.phys_dim) # nearest-neighbour term: # # S.S terms: # (s0 s1 s2 s3)_i(s0 s1 s2 s3)_j;(s0's1's2's3')_i(s0's1's2's3')_j # ^ ^ ^ ^ # s0--s1~~s0--s1 # | | | | # s2--s3 s2--s3 # i j # SiSj = torch.einsum('ijab,efgmno,qrsxyz->eifgjqrsmanobxyz', SS, id3, id3) # # SSpSSp terms: # s0--s1 s0--s1 + s0--s1==s0--s1 # | || || | | | | | # s2--s3 s2--s3 s2--s3==s2--s3 # i j i j SSpiSSpj = torch.einsum('ijklabcd,efmn,ghxy->eifjkglhmanbcxdy', SSpSSp, id2, id2) h2 = self.j1 * (SiSj + SiSj.permute(bk(0, 3, 2, 1, 6, 5, 4, 7))) - self.q_inter * (SSpiSSpj) h2+= self.j1*(SiSj.permute(bk(0,2,1,3,4,5,6,7)) + SiSj.permute(bk(0,3,2,1,5,4,6,7)))\ -self.q_inter*(SSpiSSpj.permute(bk(0,2,1,3,4,6,5,7))) h2 = h2.contiguous().view(self.phys_dim * self.phys_dim, self.phys_dim * self.phys_dim) h2_U, h2_S, h2_V = torch.svd(h2) h2_S = h2_S[h2_S > 1.0e-14] h2_U = h2_U[:, :len(h2_S)] h2_V = h2_V[:, :len(h2_S)] h2 = h2.view(self.phys_dim, self.phys_dim, self.phys_dim, self.phys_dim) return h1, h2, (h2_U, h2_S, h2_V), SS
def get_obs_ops(self): obs_ops = dict() irrep = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) obs_ops["sz"] = irrep.SZ() obs_ops["sp"] = irrep.SP() obs_ops["sm"] = irrep.SM() obs_ops["SS"] = irrep.SS() return obs_ops
def get_h(self): pd = self.phys_dim s5 = su2.SU2(pd, dtype=self.dtype, device=self.device) expr_kron = 'ij,ab->iajb' SS = torch.einsum(expr_kron,s5.SZ(),s5.SZ()) + 0.5*(torch.einsum(expr_kron,s5.SP(),s5.SM()) \ + torch.einsum(expr_kron,s5.SM(),s5.SP())) SS = SS.view(pd*pd,pd*pd) h = (1./14)*(SS + (7./10.)*SS@SS + (7./45.)*SS@SS@SS + (1./90.)*SS@SS@SS@SS) h = h.view(pd,pd,pd,pd) SS = SS.view(pd,pd,pd,pd) return h, SS
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id3 = torch.eye(8**3) id3 = id3.view(8, 8, 8, 8, 8, 8).contiguous() # h_up : on site hamiltonian in d=8 expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) -0.25*self.Hz*(torch.einsum(expr_kron,s2.SZ(),s2.I()) \ + torch.einsum(expr_kron,s2.I(),s2.SZ()) ) SS = SS.contiguous() expr_kron = 'ijab,kc->ijkabc' SSS = torch.einsum(expr_kron, SS, s2.I()) SSS = SSS + SSS.permute(2, 0, 1, 5, 3, 4) + SSS.permute( 1, 2, 0, 4, 5, 3) # -A-B- + -B-C- + -C-A- h_down = SSS.view(8, 8).contiguous() h2x2_down = torch.einsum('ia,jklbcd->ijklabcd', h_down, id3) h2x2_down= h2x2_down + h2x2_down.permute(3,0,1,2,7,4,5,6) + h2x2_down.permute(2,3,0,1,6,7,4,5)\ + h2x2_down.permute(1,2,3,0,5,6,7,4)## -A1- + -A2- + -A3- + -A4- h2x2_down = h2x2_down.contiguous() # h_down : made of 3 kinds of bonds # h_x: corresponds to h_bc terms on up triangle # h_y: corresponds to h_ca terms on up triangle # h_nnn: correspomds to h_ba terms on up triangle id4 = torch.eye(16) id4 = id4.view(2, 2, 2, 2, 2, 2, 2, 2).contiguous() h_bc = torch.einsum('ijab,klmncdef->kilmnjcadefb', SS, id4) h_ca = torch.einsum('ijab,klmncdef->klijmncdabef', SS, id4) h_ba = torch.einsum('ijab,klmncdef->kiljmncadbef', SS, id4) h_x = h_bc.contiguous().view(8, 8, 8, 8) h_y = h_ca.contiguous().view(8, 8, 8, 8) h_nnn = h_ba.contiguous().view(8, 8, 8, 8) id2 = torch.eye(8**2, dtype=self.dtype, device=self.device) id2 = id2.view(8, 8, 8, 8).contiguous() h2x2_x = torch.einsum('ijab,klcd->ijklabcd', h_x, id2) #h2x2_x= h2x2_x + h2x2_x.permute(2,3,0,1,6,7,4,5) h2x2_y = torch.einsum('ijab,klcd->ikjlacbd', h_y, id2) #h2x2_y= h2x2_y + h2x2_y.permute(1,0,3,2,5,4,7,6) h2x2_nn = h2x2_x.contiguous() + h2x2_y.contiguous() h2x2_nnn = torch.einsum('ijab,klcd->ikljacdb', h_nnn, id2) h2x2_nnn = h2x2_nnn.contiguous() Ham = (h2x2_down / 4.0 + h2x2_nn + h2x2_nnn) / 3.0 #Ham = h2x2_nnn return Ham
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() SzSz = 4 * torch.einsum('ij,ab->iajb', s2.SZ(), s2.SZ()) SzSzIdId = torch.einsum('ijab,klcd->ijklabcd', SzSz, id2) SzSzSzSz = torch.einsum('ijab,klcd->ijklabcd', SzSz, SzSz) Sx = s2.SP() + s2.SM() SxIdIdId = torch.einsum('ia,jb,kc,ld->ijklabcd', Sx, s2.I(), s2.I(), s2.I()) hp = -SzSzIdId - SzSzIdId.permute( 0, 2, 1, 3, 4, 6, 5, 7) - self.q * SzSzSzSz - self.hx * SxIdIdId return SzSz, SzSzSzSz, Sx, hp
def get_h(self): pd = self.phys_dim s5 = su2.SU2(pd, dtype=self.dtype, device=self.device) expr_kron = 'ij,ab->iajb' SS = torch.einsum(expr_kron,s5.SZ(),s5.SZ()) + 0.5*(torch.einsum(expr_kron,s5.SP(),s5.SM()) \ + torch.einsum(expr_kron,s5.SM(),s5.SP())) rot_op = s5.BP_rot() SS_rot = torch.einsum('jl,ilak,kb->ijab',rot_op,SS,rot_op) SS = SS.view(pd*pd,pd*pd) h = (1./14)*(SS + (7./10.)*SS@SS + (7./45.)*SS@SS@SS + (1./90.)*SS@SS@SS@SS) h = h.view(pd,pd,pd,pd) # apply a rotation on physical index of every "odd" site # A A => A B # A A => B A h_rot = torch.einsum('jl,ilak,kb->ijab',rot_op,h,rot_op) SS = SS.view(pd,pd,pd,pd) return h_rot, SS, SS_rot
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SSp = SS - 0.25 * id2 SSpSSp = torch.einsum('ijab,klcd->ijklabcd', SSp, SSp) SSpSSp = SSpSSp + SSpSSp.permute(0, 2, 1, 3, 4, 6, 5, 7) h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', SS, id2) hp_h_q = self.j1 * (h2x2_SS + h2x2_SS.permute(2, 3, 0, 1, 6, 7, 4, 5)) - self.q * SSpSSp hp_v_q= self.j1*(h2x2_SS.permute(0,2,1,3,4,6,5,7) + h2x2_SS.permute(2,0,3,1,6,4,7,5)) \ - self.q*SSpSSp return SS, SSpSSp, hp_h_q, hp_v_q
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(self.phys_dim**2, dtype=self.dtype, device=self.device) id2 = id2.view(tuple([self.phys_dim] * 4)).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) rot_op = s2.BP_rot() SS_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, SS, rot_op) h2x2_SS_rot = torch.einsum('ijab,klcd->ijklabcd', SS_rot, id2) # nearest neighbours h2x2_SS = torch.einsum('ijab,klcd->ikljacdb', SS, id2) # next-nearest neighbours hp= self.j1*(h2x2_SS_rot + h2x2_SS_rot.permute(0,2,1,3,4,6,5,7))\ + self.j2*(h2x2_SS + h2x2_SS.permute(1,0,3,2,5,4,7,6)) hp = hp.contiguous() return SS, SS_rot, hp
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SS = SS.contiguous() h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', SS, id2) h2x2_nn= h2x2_SS + h2x2_SS.permute(2,3,0,1,6,7,4,5) + h2x2_SS.permute(0,2,1,3,4,6,5,7)\ + h2x2_SS.permute(2,0,3,1,6,4,7,5)## --A--B-- + --C--D-- + --A--C-- + --B--D-- h2x2_nnn = h2x2_SS.permute(0, 3, 2, 1, 4, 7, 6, 5) #+ h2x2_nn = h2x2_nn.contiguous() h2x2_nnn = h2x2_nnn.contiguous() return SS, h2x2_nn, h2x2_nnn
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(self.phys_dim**2, dtype=self.dtype, device=self.device) id2 = id2.view(tuple([self.phys_dim] * 4)).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) rot_op = s2.BP_rot() SS_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, SS, rot_op) h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', SS, id2) # nearest neighbours # 0 1 0 1 0 x x x x 1 # 2 3 ... x x + 2 x + 2 3 + x 3 hp= 0.5*self.j1*(h2x2_SS + h2x2_SS.permute(0,2,1,3,4,6,5,7)\ + h2x2_SS.permute(2,3,0,1,6,7,4,5) + h2x2_SS.permute(3,1,2,0,7,5,6,4)) \ + self.j2*(h2x2_SS.permute(0,3,2,1,4,7,6,5) + h2x2_SS.permute(2,1,0,3,6,5,4,7)) hp = torch.einsum('xj,yk,ixylauvd,ub,vc->ijklabcd', rot_op, rot_op, hp, rot_op, rot_op) hp = hp.contiguous() return SS, SS_rot, hp
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(4, dtype=self.dtype, device=self.device) id2 = id2.view(2, 2, 2, 2).contiguous() expr_kron = 'ij,ab->iajb' SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) SSp = SS - 0.25 * id2 SSpSSp = torch.einsum('ijab,klcd->ijklabcd', SSp, SSp) SSpSSp = SSpSSp + SSpSSp.permute(0, 2, 1, 3, 4, 6, 5, 7) h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', SS, id2) # # i===j i---j i===j i---j # j1*( | | + || | ) - q*( | | + || || ) # k---l k---l k===l k---l # hp = self.j1 * (h2x2_SS + h2x2_SS.permute(0, 2, 1, 3, 4, 6, 5, 7)) - self.q * SSpSSp return SS, SSpSSp, hp
def energy_2x2_1site_BP(self, state, env): r""" :param state: wavefunction :param env: CTM environment :type state: IPEPS :type env: ENV :return: energy per site :rtype: float We assume 1x1 iPEPS which tiles the lattice with a bipartite pattern composed of two tensors A, and B=RA, where R rotates approriately the physical Hilbert space of tensor A on every "odd" site:: 1x1 C4v => rotation P => BIPARTITE A A A A A B A B A A A A B A B A A A A A A B A B A A A A B A B A A single reduced density matrix :py:func:`ctm.rdm.rdm2x2` of a 2x2 plaquette is used to evaluate the energy. """ if not (hasattr(self, 'h2x2_nn_rot') or hasattr(self, 'h2x2_nn_nrot')): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) rot_op = s2.BP_rot() self.h2x2_nn_rot= torch.einsum('irtlaxyd,jr,kt,xb,yc->ijklabcd',\ self.h2x2_nn,rot_op,rot_op,rot_op,rot_op) self.h2x2_nnn_rot= torch.einsum('irtlaxyd,jr,kt,xb,yc->ijklabcd',\ self.h2x2_nnn,rot_op,rot_op,rot_op,rot_op) tmp_rdm = rdm.rdm2x2((0, 0), state, env) energy_nn = torch.einsum('ijklabcd,ijklabcd', tmp_rdm, self.h2x2_nn_rot) energy_nnn = torch.einsum('ijklabcd,ijklabcd', tmp_rdm, self.h2x2_nnn_rot) energy_per_site = 2.0 * (self.j1 * energy_nn / 4.0 + self.j2 * energy_nnn / 2.0) return energy_per_site
def get_obs_ops(self): obs_ops = dict() expr_kron1 = 'ij,ab->iajb' expr_kron2 = 'ijab,kc->ijkabc' s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) obs_ops["sz_A"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.SZ(), s2.I()), s2.I()).view(8, 8).contiguous() obs_ops["sp_A"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.SP(), s2.I()), s2.I()).view(8, 8).contiguous() obs_ops["sm_A"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.SM(), s2.I()), s2.I()).view(8, 8).contiguous() obs_ops["sz_B"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.SZ()), s2.I()).view(8, 8).contiguous() obs_ops["sp_B"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.SP()), s2.I()).view(8, 8).contiguous() obs_ops["sm_B"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.SM()), s2.I()).view(8, 8).contiguous() obs_ops["sz_C"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.I()), s2.SZ()).view(8, 8).contiguous() obs_ops["sp_C"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.I()), s2.SP()).view(8, 8).contiguous() obs_ops["sm_C"] = torch.einsum( expr_kron2, torch.einsum(expr_kron1, s2.I(), s2.I()), s2.SM()).view(8, 8).contiguous() return obs_ops
def get_h(self): s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) expr_kron = 'ij,ab->iajb' SS = einsum(expr_kron,s2.SZ(),s2.SZ()) + 0.5*(einsum(expr_kron,s2.SP(),s2.SM()) \ + einsum(expr_kron,s2.SM(),s2.SP())) return SS
def __init__(self, j1=1.0, j2=0, j3=0, hz_stag= 0.0, delta_zz=1.0, \ global_args=cfg.global_args): r""" :param j1: nearest-neighbour interaction :param j2: next nearest-neighbour interaction :param hz_stag: staggered magnetic field :param delta_zz: easy-axis (nearest-neighbour) anisotropy :param global_args: global configuration :type j1: float :type j2: float :type hz_stag: float :type detla_zz: float :type global_args: GLOBALARGS Build Spin-1/2 :math:`J_1-J_2` Hamiltonian .. math:: H = J_1\sum_{<i,j>} \mathbf{S}_i.\mathbf{S}_j + J_2\sum_{<<i,j>>} \mathbf{S}_i.\mathbf{S}_j = \sum_{p} h_p on the square lattice. Where the first sum runs over the pairs of sites `i,j` which are nearest-neighbours (denoted as `<.,.>`), and the second sum runs over pairs of sites `i,j` which are next nearest-neighbours (denoted as `<<.,.>>`):: y\x _:__:__:__:_ ..._|__|__|__|_... ..._|__|__|__|_... ..._|__|__|__|_... ..._|__|__|__|_... ..._|__|__|__|_... : : : : where * :math:`h_p = J_1(S^x_{r}.S^x_{r+\vec{x}} + S^y_{r}.S^y_{r+\vec{x}} + \delta_{zz} S^z_{r}.S^z_{r+\vec{x}} + (x<->y)) + J_2(\mathbf{S}_{r}.\mathbf{S}_{r+\vec{x}+\vec{y}} + \mathbf{S}_{r+\vec{x}}.\mathbf{S}_{r+\vec{y}}) + h_stag (S^z_{r} - S^z_{r+\vec{x}} - S^z_{r+\vec{y}} + S^z_{r+\vec{x}+\vec{y}})` with indices of spins ordered as follows :math:`s_r s_{r+\vec{x}} s_{r+\vec{y}} s_{r+\vec{x}+\vec{y}}; s'_r s'_{r+\vec{x}} s'_{r+\vec{y}} s'_{r+\vec{x}+\vec{y}}` """ self.dtype = global_args.torch_dtype self.device = global_args.device self.phys_dim = 2 self.j1 = j1 self.j2 = j2 self.j3 = j3 self.hz_stag = hz_stag self.delta_zz = delta_zz self.obs_ops = self.get_obs_ops() s2 = su2.SU2(self.phys_dim, dtype=self.dtype, device=self.device) id2 = torch.eye(self.phys_dim**2, dtype=self.dtype, device=self.device) id2 = id2.view(tuple([self.phys_dim] * 4)).contiguous() expr_kron = 'ij,ab->iajb' self.SS_delta_zz= self.delta_zz*torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + \ 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) self.SS= torch.einsum(expr_kron,s2.SZ(),s2.SZ()) + \ 0.5*(torch.einsum(expr_kron,s2.SP(),s2.SM()) \ + torch.einsum(expr_kron,s2.SM(),s2.SP())) hz_2x1_nn = torch.einsum(expr_kron, s2.SZ(), s2.I()) + torch.einsum( expr_kron, s2.I(), -s2.SZ()) rot_op = s2.BP_rot() SS_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, self.SS, rot_op) SS_delta_zz_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, self.SS_delta_zz, rot_op) hz_2x1_rot = torch.einsum('ki,kjcb,ca->ijab', rot_op, hz_2x1_nn, rot_op) self.SS_rot = SS_rot.contiguous() self.SS_delta_zz_rot = SS_delta_zz_rot.contiguous() self.hz_2x1_rot = hz_2x1_rot.contiguous() h2x2_SS_delta_zz = torch.einsum('ijab,klcd->ijklabcd', self.SS_delta_zz, id2) # nearest neighbours h2x2_SS = torch.einsum('ijab,klcd->ijklabcd', self.SS, id2) # next-nearest neighbours # 0 1 0 1 0 x x x x 1 # 2 3 ... x x + 2 x + 2 3 + x 3 hp= 0.5*self.j1*(h2x2_SS_delta_zz + h2x2_SS_delta_zz.permute(0,2,1,3,4,6,5,7)\ + h2x2_SS_delta_zz.permute(2,3,0,1,6,7,4,5) + h2x2_SS_delta_zz.permute(3,1,2,0,7,5,6,4)) \ + self.j2*(h2x2_SS.permute(0,3,2,1,4,7,6,5) + h2x2_SS.permute(2,1,0,3,6,5,4,7))\ - 0.25*self.hz_stag*torch.einsum('ia,jb,kc,ld->ijklabcd',s2.SZ(),-s2.SZ(),-s2.SZ(),s2.SZ()) hp = torch.einsum('xj,yk,ixylauvd,ub,vc->ijklabcd', rot_op, rot_op, hp, rot_op, rot_op) self.hp = hp.contiguous()