def ising_impo(J, g): site = SpinHalfSite(None) Id, Sp, Sm, Sz = site.Id, site.Sp, site.Sm, 2*site.Sz Sx = Sp + Sm W = [[Id,Sx,g*Sz], [None,None,-J*Sx], [None,None,Id]] H = MPO.from_grids([site], [W], bc='infinite', IdL=0, IdR=-1) return H
def __init__(self, model_param): # 0) Read and set parameters. L = get_parameter(model_param, 'L', 1, self.__class__) bc_MPS = get_parameter(model_param, 'bc_MPS', 'finite', self.__class__) t = get_parameter(model_param, 't', 1., self.__class__) alpha = get_parameter(model_param, 'alpha', 1.0, self.__class__) delta = get_parameter(model_param, 'delta', 1.0, self.__class__) beta = get_parameter(model_param, 'beta', 1.0, self.__class__) conserve_fermionic_boson = get_parameter(model_param, \ 'conserve_fermionic_boson', 'Sz', self.__class__) conserve_spin = get_parameter(model_param, 'conserve_spin', None, self.__class__) unused_parameters(model_param, self.__class__) # 1) Sites and lattice. boson_site = SpinHalfSite(conserve=conserve_fermionic_boson, ) bond_spin = SpinHalfSite(conserve=conserve_spin) double_site = DoubleSite(site0=boson_site, site1=bond_spin, label0='0', label1='1', charges='independent') # lat = Lattice(Ls=[1], unit_cell=[bond_spin], order='default', bc_MPS=bc_MPS, # basis=None, positions=None) lat = Chain(L=L, site=double_site, bc_MPS='finite') # 2) Initialize CouplingModel bc_coupling = 'periodic' if bc_MPS == 'infinite' else 'open' CouplingModel.__init__(self, lat, bc_coupling) # 3) Build the Hamiltonian. # 3a) on-site terms self.add_onsite(delta / 2.0, 0, 'Sigmaz1') self.add_onsite(beta, 0, 'Sigmax1') # 3b) coupling terms. # 3bi) standard Bose-Hubbard coupling terms self.add_coupling(-t, 0, 'Sp0', 0, 'Sm0', 1) self.add_coupling(-t, 0, 'Sm0', 0, 'Sp0', 1) # 3bii) coupling on site bosons to bond spin self.add_coupling(-alpha, 0, 'Sp0 Sigmaz1', 0, 'Sm0', 1) self.add_coupling(-alpha, 0, 'Sm0 Sigmaz1', 0, 'Sp0', 1) # 4) Initialize MPO MPOModel.__init__(self, lat, self.calc_H_MPO()) # 5) Initialize H bond # LS: what does this mean? NearestNeighborModel.__init__(self, self.lat, self.calc_H_bond())
def init_sites(self, model_params): conserve = model_params.get('conserve', 'parity') assert conserve != 'Sz' if conserve == 'best': conserve = 'parity' if self.verbose >= 1.: print(self.name + ": set conserve to", conserve) site = SpinHalfSite(conserve=conserve) return site
def __init__(self, model_param): # model parameters L = get_parameter(model_param, 'L', 2, self.__class__) xi = get_parameter(model_param, 'xi', 0.5, self.__class__) Jxx = get_parameter(model_param, 'Jxx', 1., self.__class__) Jz = get_parameter(model_param, 'Jz', 1.5, self.__class__) hz = get_parameter(model_param, 'hz', 0., self.__class__) conserve = get_parameter(model_param, 'conserve', 'Sz', self.__class__) if xi == 0.: g = 0. elif xi == np.inf: g = 1. else: g = np.exp(-1/(xi)) unused_parameters(model_param, self.__class__) # Define the sites and the lattice, which in this case is a simple uniform chain # of spin 1/2 sites site = SpinHalfSite(conserve=conserve) lat = Chain(L, site, bc_MPS='infinite') # The operators that appear in the Hamiltonian. Standard spin operators are # already defined for the spin 1/2 site, but it is also possible to add new # operators using the add_op method Sz, Sp, Sm, Id = site.Sz, site.Sp, site.Sm, site.Id # yapf:disable # The grid (list of lists) that defines the MPO. It is possible to define the # operators in the grid in the following ways: # 1) NPC arrays, defined above: grid = [[Id, Sp, Sm, Sz, -hz*Sz ], [None, g*Id, None, None, 0.5*Jxx*Sm], [None, None, g*Id, None, 0.5*Jxx*Sp], [None, None, None, g*Id, Jz*Sz ], [None, None, None, None, Id ]] # 2) In the form [("OpName", strength)], where "OpName" is the name of the # operator (e.g. "Sm" for Sm) and "strength" is a number that multiplies it. grid = [[[("Id", 1)], [("Sp",1)], [("Sm",1)], [("Sz",1)], [("Sz", -hz)] ], [None , [("Id",g)], None , None , [("Sm", 0.5*Jxx)]], [None , None , [("Id",g)], None , [("Sp", 0.5*Jxx)]], [None , None , None , [("Id",g)], [("Sz",Jz)] ], [None , None , None , None , [("Id",1)] ]] # 3) It is also possible to write a single "OpName", equivalent to # [("OpName", 1)]. grid = [["Id" , "Sp" , "Sm" , "Sz" , [("Sz", -hz)] ], [None , [("Id",g)], None , None , [("Sm", 0.5*Jxx)]], [None , None , [("Id",g)], None , [("Sp", 0.5*Jxx)]], [None , None , None , [("Id",g)], [("Sz",Jz)] ], [None , None , None , None , "Id" ]] # yapf:enable grids = [grid]*L # Generate the MPO from the grid. Note that it is not necessary to specify # the physical legs and their charges, since the from_grids method can extract # this information from the position of the operators inside the grid. H = MPO.from_grids(lat.mps_sites(), grids, bc='infinite', IdL=0, IdR=-1) MPOModel.__init__(self, lat, H)
def init_sites(self, model_params): # conserve = get_parameter(model_params, 'conserve', 'parity', self.name) # assert conserve != 'Sz' # if conserve == 'best': # conserve = 'parity' # if self.verbose >= 1.: # print(self.name + ": set conserve to", conserve) site = SpinHalfSite(conserve=None) return site
def ising_mpo(J, g, N, bc='finite'): site = SpinHalfSite(None) Id, Sp, Sm, Sz = site.Id, site.Sp, site.Sm, 2*site.Sz Sx= Sp + Sm # confirmed from TeNPy docs, lines below directly copied from docs W_bulk = [[Id,Sx,g*Sz],[None,None,-J*Sx],[None,None,Id]] W_first = [W_bulk[0]] # first row W_last = [[row[-1]] for row in W_bulk] # last column Ws = [W_first] + [W_bulk]*(N-2) + [W_last] H = MPO.from_grids([site]*N, Ws, bc, IdL=0, IdR=-1) # (probably leave the IdL,IdR) return H
def xxz_mpo(J=1.0, Delta=1.0, hz=0.2, N=4, bc='finite'): site = SpinHalfSite(None) Id, Sp, Sm, Sz = site.Id, site.Sp, site.Sm, 2*site.Sz W_bulk = [[Id, Sp, Sm, Sz, -hz * Sz], [None, None, None, None, 0.5 * J * Sm], [None, None, None, None, 0.5 * J * Sp], [None, None, None, None, J * Delta * Sz], [None, None, None, None, Id]] W_first = [W_bulk[0]] # first row W_last = [[row[-1]] for row in W_bulk] # last column Ws = [W_first] + [W_bulk]*(N - 2) + [W_last] H = MPO.from_grids([site]*N, Ws, bc, IdL=0, IdR=-1) # (probably leave the IdL,IdR) return H
def circuit_mps(params, circuit, N, bc='finite'): site = SpinHalfSite(None) tensors = [circuit.get_tensor(params)]*N B_arrs = [np.swapaxes(tensor[:,:,0,:],1,2) for tensor in tensors] B_arrs[0] = B_arrs[0][:,0:1,:] B_arrs[-1] = B_arrs[-1][:,:,0:1] psi = MPS.from_Bflat([site]*N, B_arrs, bc, dtype=complex, form=None) if psi.form is not None: try: psi.canonical_form() psi.convert_form(psi.form) except: print("psi form thing didn't work") return psi
def circuit_imps(params, circuit): site = SpinHalfSite(None) # evaluate circuit, get rank-4 (p_out, b_out, p_in, b_in) unitary unitary = circuit.get_tensor(params) # change the order of indices to [p, vL, vR] = [p_out, b_in, b_out] # (with p_in = 0 to go from unitary to isometry) B = [np.swapaxes(unitary[:,:,0,:],1,2)] psi = MPS.from_Bflat([site], B, bc='infinite', dtype=complex, form=None) if psi.form is not None: try: psi.canonical_form() psi.convert_form(psi.form) except: print("psi form thing didn't work") return psi
def test_RandomUnitaryEvolution(): L = 8 spin_half = SpinHalfSite(conserve='Sz') psi = MPS.from_product_state([spin_half] * L, [0, 1] * (L // 2), bc='finite') # Neel state assert tuple(psi.chi) == (1, 1, 1, 1, 1, 1, 1) TEBD_params = dict(N_steps=2, trunc_params={'chi_max': 10}) eng = tebd.RandomUnitaryEvolution(psi, TEBD_params) eng.run() print(eng.psi.chi) assert tuple(eng.psi.chi) == (2, 4, 8, 10, 8, 4, 2) # infinite versions TEBD_params['trunc_params']['chi_max'] = 20 psi = MPS.from_product_state([spin_half] * 2, [0, 0], bc='infinite') eng = tebd.RandomUnitaryEvolution(psi, TEBD_params) eng.run() print(eng.psi.chi) assert tuple(eng.psi.chi) == (1, 1) # all up can not be changed eng.psi = MPS.from_product_state([spin_half] * 2, [0, 1], bc='infinite') eng.run() print(eng.psi.chi) assert tuple(eng.psi.chi) == (16, 8)
# some more imports from tenpy.networks.site import SpinHalfSite from tenpy.models.lattice import Chain from tenpy.networks.mps import MPS from tenpy.networks.mpo import MPO, MPOEnvironment from tenpy.algorithms.truncation import svd_theta # model parameters Jxx, Jz = 1., 1. L = 20 dt = 0.1 cutoff = 1.e-10 print("Jxx={Jxx}, Jz={Jz}, L={L:d}".format(Jxx=Jxx, Jz=Jz, L=L)) print("1) create Arrays for an Neel MPS") site = SpinHalfSite(conserve='Sz') # predefined charges and Sp,Sm,Sz operators p_leg = site.leg chinfo = p_leg.chinfo # make lattice from unit cell and create product state MPS lat = Chain(L, site, bc_MPS='finite') state = ["up", "down"] * (L // 2) + ["up"] * (L % 2) # Neel state print("state = ", state) psi = MPS.from_product_state(lat.mps_sites(), state, lat.bc_MPS) print("2) create an MPO representing the AFM Heisenberg Hamiltonian") # predefined physical spin-1/2 operators Sz, S+, S- Sz, Sp, Sm, Id = site.Sz, site.Sp, site.Sm, site.Id mpo_leg = npc.LegCharge.from_qflat(chinfo, [[0], [2], [-2], [0], [0]])
"""Initialization of sites, MPS and MPO.""" # Copyright 2019 TeNPy Developers, GNU GPLv3 from tenpy.networks.site import SpinHalfSite from tenpy.networks.mps import MPS from tenpy.networks.mpo import MPO spin = SpinHalfSite(conserve="Sz") print(spin.Sz.to_ndarray()) # [[ 0.5 0. ] # [ 0. -0.5]] N = 6 # number of sites sites = [spin] * N # repeat entry of list N times pstate = ["up", "down"] * (N // 2) # Neel state psi = MPS.from_product_state(sites, pstate, bc="finite") print("<Sz> =", psi.expectation_value("Sz")) # <Sz> = [ 0.5 -0.5 0.5 -0.5] print("<Sp_i Sm_j> =", psi.correlation_function("Sp", "Sm"), sep="\n") # <Sp_i Sm_j> = # [[1. 0. 0. 0. 0. 0.] # [0. 0. 0. 0. 0. 0.] # [0. 0. 1. 0. 0. 0.] # [0. 0. 0. 0. 0. 0.] # [0. 0. 0. 0. 1. 0.] # [0. 0. 0. 0. 0. 0.]] # define an MPO Id, Sp, Sm, Sz = spin.Id, spin.Sp, spin.Sm, spin.Sz J, Delta, hz = 1., 1., 0.2 W_bulk = [[Id, Sp, Sm, Sz, -hz * Sz], [None, None, None, None, 0.5 * J * Sm],
def network_from_cells(self, network_type, L, chi_MPO=None, params=None, bdry_vecs=None, method=None, T=None): """ Returns network of finite thermal-holographic Matrix Product State (random-holoMPS), finite holo-MPS, finite holographic Matrix Product Operator (holoMPO), or MPO of a given model. -------------- Inputs: --the input assumes the list of unitary tensors at each unit-cell or rank-4 numpy.ndarray-- network_type: str One of "random_state", "circuit_MPS", "circuit_MPO", or "MPO" options. L: int Length (number) of repetitions of unit cell in the main network chain. chi_MPO: int Bond leg dimension for MPO-based structures. params: numpy.ndarray Optimized parameters for unitary structure and probability weights. bdry_vecs: list List of left (first element) and right (second element) boundary vectors. (must be set to [None,None] by default, which gives left and right boundary vectors = |0> for MPO-based structures. For holoMPS-based structures, the default [None,None] would give left boundary = |0> while the right boundary is traced over). method: str One of "thermal_state_class" or "tenpy" options. (if set to "tenpy", the returned structure would be one of physics-TenPy networks). This option is currently only available for "random_state", "circuit_MPS", and "MPO" options. T: float Temperature (for thermal-holoMPS option). Note: -For random_state, circuit_MPS and circuit_MPO options, the original circuit with parameters must be inserted as args. In this case, the returned list of bulk tensors includes rank-3 numpy.ndarray for random_state/circuit_MPS and rank-4 numpy.ndarray for circuit_MPO. -For holoMPS-based structures, the index ordering is: site, physical_out, bond-in, bond-out while for holoMPO-based structures, the index ordering is: physical-out, bond-out, physical-in, bond-in (with "in/out" referring to right canonical form ordering). -For MPO structures constructed by "thermal_state_class method", the unit cell tensor of MPO network must be inserted as arg (e.g. Hamiltonian unit cell). In this case, the bulk tensors would be rank-4 numpy.ndarray (consistent with final structure of MPO). For "tenpy"-method-based structures, the list of bulk tensors must be inserted (see TeNPy docs for more detail). -Tracing over right boundary for holoMPS-based structures is appropriate for holographic simulations. -Set bdry_vecs to None by default for "tenpy" method. Set method to None for holoMPO-based structures. """ # for circuit-based structures: # both circuit and params must be included if network_type == 'random_state' or network_type == 'circuit_MPS' or network_type == 'circuit_MPO': l_uc = len(self) # length of unit-cell N = l_uc * L # number of sites unitary_list = L * self # list of unitaries # if network_type is set to random-holoMPS: if network_type == 'random_state': # defining tensor dimensions tensor = np.swapaxes(unitary_list[0][:,:,0,:],1,2) # change to MPS-based structure d = tensor[:,0,0].size # physical leg dimension (for random state) chi = tensor[0,:,0].size # bond leg dimension (for random state) if T == 0: tensor_list1 = [np.swapaxes(unitary[:,:,0,:],1,2) for unitary in unitary_list] else: # list of variational probability weights and random selections at each site probs_list = L * thermal_state.prob_list(self,params,T) random_list = [random.choice(p) for p in probs_list] index_list = [probs_list[j].index(random_list[j]) for j in range(N)] tensor_list1 = [np.swapaxes(unitary[:,:,j,:],1,2) for unitary,j in zip(unitary_list, index_list)] # if network_type is set to holoMPS: elif network_type == 'circuit_MPS': # defining tensor dimensions tensor = np.swapaxes(unitary_list[0][:,:,0,:],1,2) # change to MPS-based structure d = tensor[:,0,0].size # physical leg dimension (for random state) chi = tensor[0,:,0].size # bond leg dimension (for random state) # bulk tensors of holoMPS structure tensor_list1 = [np.swapaxes(unitary[:,:,0,:],1,2) for unitary in unitary_list] # if network_type is set to circuit_MPO # this option assumes original, circuit-based MPO structures (e.g. holoMPO) elif network_type == 'circuit_MPO': # defining tensor dimensions (consistent with rank-4 structures) # index ordering consistent with holographic-based MPO structures d = unitary_list[0][:,0,0,0].size # physical leg dimension (for MPO) chi = unitary_list[0][0,:,0,0].size # bond leg dimension (for MPO) tensor_list1 = unitary_list # testing boundary conditions if network_type == 'random_state' or network_type == 'circuit_MPS': # specific to holoMPS-based structures if method == 'tenpy': # based on previous circuit file tensor_list1[0] = tensor_list1[0][:,0:1,:] tensor_list1[-1] = tensor_list1[-1][:,:,0:1] site = SpinHalfSite(None) M = MPS.from_Bflat([site]*N, tensor_list1, bc='finite', dtype=complex, form=None) MPS.canonical_form_finite(M,renormalize=True,cutoff=0.0) elif method == 'thermal_state_class': bdry = [] # if boundary vectors are not specified for holoMPS-based structures: # checking left boundary vector # if left boundary vector not specified, set to (1,0,0,0...) if np.array(bdry_vecs[0] == None).all(): bdry += [np.zeros(chi)] bdry[0][0] = 1 else: if bdry_vecs[0].size != chi: raise ValueError('left boundary vector different size than bulk tensors') bdry += [bdry_vecs[0]] # checking right boundary vector (special to holoMPS-based structures) if np.array(bdry_vecs[1] == None).all(): bdry += [None] else: if bdry_vecs[1].size != chi: raise ValueError('right boundary vector different size than bulk tensors') bdry += [bdry_vecs[1]] # if both boundary vectors are specified for j in range(2): if np.array(bdry_vecs[j] != None).all() and bdry_vecs[j].size == chi: bdry.append(bdry_vecs[j]) M = [[bdry[0]],tensor_list1,[bdry[1]]] # final state structure else: raise ValueError('only one of "thermal_state_class" or "tenpy" options') elif network_type == 'circuit_MPO': # specific to holoMPO-based structures bdry = [] for j in range(2): # if both boundary vectors are specified if np.array(bdry_vecs[j] != None).all() and bdry_vecs[j].size == chi: bdry.append(bdry_vecs[j]) # if boundary vectors not specified, set to (1,0,0,0...) elif np.array(bdry_vecs[j] == None).all(): bdry += [np.zeros(chi)] bdry[j][0] = 1 else: if bdry_vecs[j].size != chi: raise ValueError('boundary vectors different size than bulk tensors') bdry += [bdry_vecs[j]] M = [[bdry[0]],tensor_list1,[bdry[1]]] # final state structure # if network_type is set to MPO: # this option assumes genuine MPO_based structures (e.g. Hamiltonian MPO) elif network_type == 'MPO': if method == 'tenpy': # tenpy-based MPO site = SpinHalfSite(None) M = MPO.from_grids([site]*L, self, bc = 'finite', IdL=0, IdR=-1) elif method == 'thermal_state_class': # only bulk tensors of the main chain must be included (w/out params) tensor_list1 = [self]*L # testing boundary conditions bdry = [] for j in range(2): # if both boundary vectors are specified if np.array(bdry_vecs[j] != None).all() and bdry_vecs[j].size == chi_MPO: bdry.append(bdry_vecs[j]) # if boundary vectors not specified, set to (1,0,0,0...) elif np.array(bdry_vecs[j] == None).all(): bdry += [np.zeros(chi_MPO)] bdry[j][0] = 1 else: if bdry_vecs[j].size != chi_MPO: raise ValueError('boundary vectors different size than bulk tensors') bdry += [bdry_vecs[j]] M = [[bdry[0]],tensor_list1,[bdry[1]]] # final state structure else: raise ValueError('only one of "thermal_state_class" or "tenpy" options') else: raise ValueError('only one of "random_state", "circuit_MPS", "circuit_MPO", "MPO" options') return M