Source code for ipeps.ipeps_abelian_c4v

from collections import OrderedDict
from itertools import chain
import json
import itertools
import math
import warnings
try:
    import torch
except ImportError as e:
    warnings.warn("torch not available", Warning)
import config as cfg
import yast.yast as yast
from ipeps.ipeps_abelian import IPEPS_ABELIAN, write_ipeps
from groups.pg_abelian import make_c4v_symm_A1
from ipeps.tensor_io import *

[docs]class IPEPS_ABELIAN_C4V(IPEPS_ABELIAN): _REF_S_DIRS=(1,1,1,1,1) def __init__(self, settings, site=None, peps_args=cfg.peps_args, global_args=cfg.global_args): r""" :param settings: YAST configuration :type settings: NamedTuple or SimpleNamespace (TODO link to definition) :param site: on-site tensor :param peps_args: ipeps configuration :param global_args: global configuration :type settings: TODO :type site: yast.Tensor :type peps_args: PEPSARGS :type global_args: GLOBALARGS The index-position convetion for on-site tensor is defined as follows:: (+1)u (+1)s |/ (+1)l--a--(+1)r <=> a[s,u,l,d,r] with reference symmetry signature [1,1,1,1,1] | (+1)d where s denotes physical index, and u,l,d,r label four principal directions up, left, down, right in anti-clockwise order starting from up. .. note:: This signature convention leads to the `bra` interpretation of physical space. The on-site tensor is to be understood as :math:`a=\sum_{suldr} a_{suldr} \langle s|\langle u|\langle l|\langle d|\langle r|` """ def vertexToSite(coord): return (0,0) sites= dict() if not (site is None): sites= OrderedDict({(0,0): site}) super().__init__(settings, sites, vertexToSite=vertexToSite, lX=1, lY=1,\ peps_args=peps_args, global_args=global_args)
[docs] def site(self, coord=(0,0)): return super().site(coord)
[docs] def to(self, device): r""" :param device: device identifier :type device: str :return: returns a copy of the state on ``device``. If the state already resides onthe `device` returns ``self``. :rtype: IPEPS_ABELIAN_C4V Move the entire state to ``device``. """ if device==self.device: return self site= self.site().to(device) state= IPEPS_ABELIAN_C4V(self.engine, site) return state
[docs] def to_dense(self): r""" :return: returns a copy of the state with all on-site tensors in their dense representation. If the state already has just dense on-site tensors returns ``self``. :rtype: IPEPS_ABELIAN_C4V Create a copy of state with all on-site tensors as dense possesing no explicit block structure (symmetry). .. note:: This operations preserves gradients on returned dense state. """ if self.nsym==0: return self site_dense= self.site().to_nonsymmetric() settings_dense= site_dense.config state_dense= IPEPS_ABELIAN_C4V(settings_dense, site_dense) return state_dense
[docs] def write_to_file(self, outputfile, tol=None, symmetrize=True, normalize=False): """ Writes state to file. See :meth:`ipeps.ipeps_abelian.write_ipeps`. """ sym_state= self.symmetrize() if symmetrize else self write_ipeps(sym_state, outputfile, tol=tol, normalize=normalize)
[docs] def symmetrize(self): r""" :return: symmetrize on-site tensor by projecting to :math:`A_1` irrep of C4v point group. :rtype: IPEPS_ABELIAN_C4V """ site= make_c4v_symm_A1(self.site()) state= IPEPS_ABELIAN_C4V(self.engine, site) return state
# NOTE what about non-initialized blocks, which are however allowed by the symmetry ?
[docs] def add_noise(self, noise=0): r""" :param noise: magnitude of the noise :type noise: float :return: a copy of state with noisy on-site tensors. For default value of ``noise`` being zero ``self`` is returned. :rtype: IPEPS_ABELIAN_C4V Create a new state by adding random uniform noise with magnitude ``noise`` to all copies of on-site tensors. The noise is added to all blocks making up the individual on-site tensors. """ if noise==0: return self _tmp= self.site() t_data, D_data= _tmp.get_leg_charges_and_dims(native=True) t_noise= yast.rand(config=_tmp.config, s=_tmp.s, n=_tmp.n, \ t=t_data, D=D_data, isdiag=_tmp.isdiag) site= _tmp + noise * t_noise state= IPEPS_ABELIAN_C4V(self.engine, site) state= state.symmetrize() return state
def __str__(self): print(f"lX x lY: {self.lX} x {self.lY}") for nid,coord,site in [(t[0], *t[1]) for t in enumerate(self.sites.items())]: print(f"a{nid} {coord}: {site}") # show tiling of a square lattice coord_list = list(self.sites.keys()) mx, my = 3*self.lX, 3*self.lY label_spacing = 1+int(math.log10(len(self.sites.keys()))) for y in range(-my,my): if y == -my: print("y\\x ", end="") for x in range(-mx,mx): print(str(x)+label_spacing*" "+" ", end="") print("") print(f"{y:+} ", end="") for x in range(-mx,mx): print(f"a{coord_list.index(self.vertexToSite((x,y)))} ", end="") print("") return ""
[docs]def read_ipeps_c4v(jsonfile, settings, \ peps_args=cfg.peps_args, global_args=cfg.global_args): r""" :param jsonfile: input file describing IPEPS_ABELIAN_C4V in json format :param settings: YAST configuration :type settings: NamedTuple or SimpleNamespace (TODO link to definition) :param peps_args: ipeps configuration :param global_args: global configuration :type jsonfile: str or Path object :type peps_args: PEPSARGS :type global_args: GLOBALARGS :return: wavefunction :rtype: IPEPS_ABELIAN_C4V Read state in JSON format from file. """ sites = OrderedDict() with open(jsonfile) as j: raw_state = json.load(j) # Loop over non-equivalent tensor,site pairs in the unit cell for ts in raw_state["map"]: coord = (ts["x"],ts["y"]) # find the corresponding tensor (and its elements) # identified by "siteId" in the "sites" list t = None for s in raw_state["sites"]: if s["siteId"] == ts["siteId"]: t = s if t == None: raise Exception("Tensor with siteId: "+ts["sideId"]+" NOT FOUND in \"sites\"") # depending on the "format", read the bare tensor if "format" in t.keys(): if t["format"]=="abelian": X= read_json_abelian_tensor_legacy(t, settings) else: raise Exception("Unsupported format "+t["format"]) else: warnings.warn("\"format\" not specified. Assuming dense tensor", Warning) t["charges"]=[] if not "dims" in t.keys(): # assume legacy keys t["dims"]= [t["physDim"]]+[t["auxDim"]]*4 if not "dtype" in t.keys(): t["dtype"]= "float64" tmp_t= {"blocks": [t]} tmp_t["format"]="abelian" tmp_t["dtype"]= "float64" tmp_t["nsym"]=0 tmp_t["symmetry"]=[] tmp_t["signature"]= IPEPS_ABELIAN_C4V._REF_S_DIRS tmp_t["n"]=0 tmp_t["isdiag"]=False tmp_t["rank"]= len(t["dims"]) X= read_json_abelian_tensor_legacy(tmp_t, settings) sites[coord]= X assert len(sites)==1, "Invalid number of on-site tensors. Expected one." site= next(iter(sites.values())) state = IPEPS_ABELIAN_C4V(settings, site, \ peps_args=peps_args, global_args=global_args) # check dtypes of all on-site tensors for newly created state assert (False not in [state.dtype==s.yast_dtype for s in sites.values()]), \ "incompatible dtype among state and on-site tensors" # move to desired device and return return state.to(global_args.device)