Source code for ctm.one_site_c4v.env_c4v

import torch
import config as cfg
from ipeps.ipeps_c4v import IPEPS_C4V
import pdb

[docs]class ENV_C4V(): def __init__(self, chi, state=None, bond_dim=None, ctm_args=cfg.ctm_args, global_args=cfg.global_args): r""" :param chi: environment bond dimension :math:`\chi` :param state: wavefunction :param bond_dim2: bond dimension :param ctm_args: CTM algorithm configuration :param global_args: global configuration :type chi: int :type state: IPEPS_C4V :type bond_dim: int :type ctm_args: CTMARGS :type global_args: GLOBALARGS Assuming C4v symmetric single-site ``state`` create corresponding half-row(column) tensor T and corner tensor C. The corner tensor has dimensions :math:`\chi \times \chi` and the half-row(column) tensor has dimensions :math:`\chi \times \chi \times D^2` with :math:`D` given by ``state`` or ``bond_dim``:: y\x -1 0 1 -1 C T C 0 T A T 1 C T C If both ``state`` and ``bond_dim`` are supplied, the ``bond_dim`` parameter is ignored. The environment tensors of an ENV object ``e`` are accesed through members ``C`` and ``T`` The index-position convention is as follows: For upper left C and left T start from the index in the **direction "up"** <=> (-1,0) and continue **anti-clockwise**:: C--1 0--T--1 0--C | | | 0 2 1 0 0 | | T--2 2--T | | 1 1 0 2 0 | | | C--1 0--T--1 1--C All C's and T's in the above diagram are identical and they are symmetric under the exchange of environment bond indices :math:`C_{ij}=C_{ji}` and :math:`T_{ija}=C_{jia}`. """ assert state or bond_dim, "either state or bond_dim must be supplied" if state: assert len(state.sites)==1, "Not a 1-site ipeps" site= next(iter(state.sites.values())) assert site.size()[1]==site.size()[1]==site.size()[1]==site.size()[1],\ "bond dimensions of on-site tensor are not equal" bond_dim= site.size()[1] super(ENV_C4V, self).__init__() self.dtype= global_args.dtype self.device= global_args.device self.chi= chi self.bond_dim= bond_dim # initialize environment tensors # The same structure is preserved as for generic ipeps ``ENV``. We store keys for access # to dummy dicts ``C`` and ``T`` self.keyC= ((0,0),(-1,-1)) self.keyT= ((0,0),(-1,0)) self.C= dict() self.T= dict() self.C[self.keyC]= torch.zeros((self.chi,self.chi), dtype=self.dtype, device=self.device) self.T[self.keyT]= torch.zeros((self.chi,self.chi,bond_dim**2), \ dtype=self.dtype, device=self.device) def get_C(self): r""" :return: get corner tensor :rtype: torch.Tensor """ return self.C[self.keyC] def get_T(self): r""" :return: get half-row/-column tensor :rtype: torch.Tensor """ return self.T[self.keyT] def extend(self, new_chi, ctm_args=cfg.ctm_args, global_args=cfg.global_args): new_env= ENV_C4V(new_chi, bond_dim=self.bond_dim, ctm_args=ctm_args, global_args=global_args) x= min(self.chi, new_chi) new_env.C[new_env.keyC][:x,:x]= self.get_C()[:x,:x] new_env.T[new_env.keyT][:x,:x,:self.bond_dim**2]= self.get_T()[:x,:x,:self.bond_dim**2] return new_env
[docs]def init_env(state, env, ctm_args=cfg.ctm_args): """ :param state: wavefunction :param env: C4v symmetric CTM environment :param ctm_args: CTM algorithm configuration :type state: IPEPS_C4V :type env: ENV_C4V :type ctm_args: CTMARGS Initializes the environment `env` according to one of the supported options specified inside :class:`CTMARGS.ctm_env_init_type <config.CTMARGS>` * CONST - C and T tensors have all their elements intialized to a value 1 * RANDOM - C and T tensors have elements with random numbers drawn from uniform distribution [0,1) * CTMRG - tensors C and T are built from the on-site tensor of `state` """ if ctm_args.ctm_env_init_type=='CONST': init_const(env, ctm_args.verbosity_initialization) elif ctm_args.ctm_env_init_type=='RANDOM': init_random(env, ctm_args.verbosity_initialization) elif ctm_args.ctm_env_init_type=='CTMRG': init_from_ipeps_pbc(state, env, ctm_args.verbosity_initialization) elif ctm_args.ctm_env_init_type=='CTMRG_OBC': init_from_ipeps_obc(state, env, ctm_args.verbosity_initialization) else: raise ValueError("Invalid environment initialization: "+str(ctm_args.ctm_env_init_type))
def init_const(env, verbosity=0): for key,t in env.C.items(): env.C[key]= torch.ones(t.size(), dtype=env.dtype, device=env.device) for key,t in env.T.items(): env.T[key]= torch.ones(t.size(), dtype=env.dtype, device=env.device) # TODO restrict random corners to have pos-semidef spectrum def init_random(env, verbosity=0): for key,t in env.C.items(): tmpC= torch.rand(t.size(), dtype=env.dtype, device=env.device) env.C[key]= 0.5*(tmpC+tmpC.t()) for key,t in env.T.items(): env.T[key]= torch.rand(t.size(), dtype=env.dtype, device=env.device) # TODO handle case when chi < bond_dim^2 def init_from_ipeps_pbc(state, env, verbosity=0): if verbosity>0: print("ENV: init_from_ipeps_pbc") # Left-upper corner # # i = C--1 # j--A--3 0 # /\ # 2 m # \ i # j--A--3 # / # 2 A= next(iter(state.sites.values())) dimsA= A.size() a= torch.einsum('mijef,mijab->eafb',(A,A)).contiguous().view(dimsA[3]**2, dimsA[4]**2) a= a/torch.max(torch.abs(a)) env.C[env.keyC]= torch.zeros(env.chi,env.chi, dtype=env.dtype, device=env.device) env.C[env.keyC][:min(env.chi,dimsA[3]**2),:min(env.chi,dimsA[4]**2)]=\ a[:min(env.chi,dimsA[3]**2),:min(env.chi,dimsA[4]**2)] # left transfer matrix # # 0 = 0 # i--A--3 T--2 # /\ 1 # 2 m # \ 0 # i--A--3 # / # 2 a = torch.einsum('meifg,maibc->eafbgc',(A,A)).contiguous().view(dimsA[1]**2, dimsA[3]**2, dimsA[4]**2) a= a/torch.max(torch.abs(a)) env.T[env.keyT]= torch.zeros((env.chi,env.chi,dimsA[4]**2), dtype=env.dtype, device=env.device) env.T[env.keyT][:min(env.chi,dimsA[1]**2),:min(env.chi,dimsA[3]**2),:]=\ a[:min(env.chi,dimsA[1]**2),:min(env.chi,dimsA[3]**2),:] # TODO handle case when chi < bond_dim^2 def init_from_ipeps_obc(state, env, verbosity=0): if verbosity>0: print("ENV: init_from_ipeps_obc") # Left-upper corner # # i = C--1 # j--A--3 0 # /\ # 2 m # \ k # l--A--3 # / # 2 A= next(iter(state.sites.values())) dimsA= A.size() a= torch.einsum('mijef,mklab->eafb',(A,A)).contiguous().view(dimsA[3]**2, dimsA[4]**2) a= a/torch.max(torch.abs(a)) env.C[env.keyC]= torch.zeros(env.chi,env.chi, dtype=env.dtype, device=env.device) env.C[env.keyC][:min(env.chi,dimsA[3]**2),:min(env.chi,dimsA[4]**2)]=\ a[:min(env.chi,dimsA[3]**2),:min(env.chi,dimsA[4]**2)] # left transfer matrix # # 0 = 0 # i--A--3 T--2 # /\ 1 # 2 m # \ 0 # k--A--3 # / # 2 a= torch.einsum('meifg,makbc->eafbgc',(A,A)).contiguous().view(dimsA[1]**2, dimsA[3]**2, dimsA[4]**2) a= a/torch.max(torch.abs(a)) env.T[env.keyT]= torch.zeros((env.chi,env.chi,dimsA[4]**2), dtype=env.dtype, device=env.device) env.T[env.keyT][:min(env.chi,dimsA[1]**2),:min(env.chi,dimsA[3]**2),:]=\ a[:min(env.chi,dimsA[1]**2),:min(env.chi,dimsA[3]**2),:] def print_env(env, verbosity=0): print("dtype "+str(env.dtype)) print("device "+str(env.device)) print("C "+str(env.C[env.keyC].size())) if verbosity>0: print(env.C[env.keyC]) print("T "+str(env.T[env.keyT].size())) if verbosity>0: print(env.T[env.keyT]) def compute_multiplets(env, eps_multiplet_gap=1.0e-10): D= torch.zeros(env.chi+1, dtype=env.dtype, device=env.device) D[:env.chi], U= torch.symeig(env.C[env.keyC]) D, p= torch.sort(torch.abs(D),descending=True) m=[] l=0 for i in range(env.chi): l+=1 g=D[i]-D[i+1] #print(f"{i} {D[i]} {g}", end=" ") if g>eps_multiplet_gap: #print(f"{l}", end=" ") m.append(l) l=0 return m