def check_mps_norm1(self, if_print=False): # check if the MPS is norm-1 norm = self.norm_mps() if abs(norm - 1) > 1e-14: print_error('The norm is MPS is %g away from 1' % abs(norm - 1)) if if_print: cprint('The norm of MPS is %g' % norm, 'cyan')
def update_effect_from_op1_to_op2(self, sn, snn, p0, q0, p1): # here, we have p0 < q0 < p1, or p1 >= q0 > p0 (on the same side of the RG endpoint) if q0 < p1: v = self.get_effective_operators_one_body(sn, p0, q0) v = T_module.bound_vec_operator_left2right(self.mps[q0], self.operators[snn], v) self.add_key_and_pos('two', (sn, snn, p0, q0, q0 + 1), v) for n in range(q0 + 1, p1): v = self.update_effect_op_l0_to_l1(n, n + 1, v, is_update_op=False) self.add_key_and_pos('two', (sn, snn, p0, q0, n + 1), v) elif p1 <= p0: v = self.get_effective_operators_one_body(snn, q0, p0 + 1) v = T_module.bound_vec_operator_right2left(self.mps[p0], self.operators[sn], v) self.add_key_and_pos('two', (sn, snn, p0, q0, p0), v) for n in range(p0 - 1, p1 - 1, -1): v = self.update_effect_op_l0_to_l1(n, n - 1, v, is_update_op=False) self.add_key_and_pos('two', (sn, snn, p0, q0, n), v) else: # if this happen, there must be a logic bug v = None print_error('LogicBug detected. Please check') return v
def absorb_matrices2tensor(tensor, mats, bonds=np.zeros(0), mat_bond=-1): # default: contract the 1st bond of mat with tensor nm = len(mats) # number of matrices to be contracted if is_debug: if nm != tensor.ndim: print_error( 'InputError: the number of matrices should be equal to the number of indexes of tensor' ) if bonds.size == 0: # set default of bonds: contract all matrices in order, starting from the 0th bond bonds = np.arange(0, nm) if mat_bond < 0: # set default of mat_bond: contract the 1st bond of each matrix mat_bond = np.zeros((nm, 1)) for i in range( 0, nm): # permute if the second bond of a matrix is to be contracted if mat_bond[i, 0] == 1: mats[i] = mats[i].T # check if full_fast function can be used if np.array_equiv(np.sort(bonds), np.arange(0, nm)): order = np.argsort(bonds) mats = sort_list(mats, order) # this full_fast function can be used when each bond has a matrix which are arranged in the correct order tensor = absorb_matrices2tensor_full_fast(tensor, mats) else: # can be optimized for i in range(0, nm): tensor = absorb_matrix2tensor(tensor, mats[i], bonds[i]) return tensor
def get_effective_operator_two_body(self, sn, snn, p0, q0, p1): # the self.operators[sn] is originally at p0-th site # the self.operators[ssn] is originally at q0-th site # the effective two-body operator is at the p1-th bond # here, we have p0 < q0 <= p1, or p1 >= q0 > p0 (on the same side of the RG endpoint) if p0 > q0: # make sure p0 < q0 p0, q0 = q0, p0 sn, snn = snn, sn key2 = self.key_effective_operators((sn, snn, p0, q0, p1)) if key2 in self.effect_ss: return self.effect_ss[key2] elif q0 == p1: print_error('LogicBug detected: please check') else: return self.update_effect_from_op1_to_op2(sn, snn, p0, q0, p1)
def update_tensor_handle_dmrg_1site(self, tensor, p, operators, index1, index2, coeff1, coeff2, tau, tol=1e-12): # Very inefficient!!! # function handle to put in eigs, to update the p-th tensor # index1: one-body interactions, index2: two-body interactions # one-body terms: index1[n, 1]-th operator is at the index1[n, 0]-th site # tne-body terms: index2[n, 2]-th operator is at the index2[n, 0]-th site # tne-body terms: index2[n, 3]-th operator is at the index2[n, 1]-th site if self._debug and p != self.center: print_error( 'CenterError: the tensor must be at the orthogonal center before ' 'defining the function handle', 'magenta') tensor = tensor.reshape(self.virtual_dim[p], self.phys_dim, self.virtual_dim[p + 1]) tensor1 = tensor.copy() nh1 = index1.shape[0] # number of two-body Hamiltonians for n in range(0, nh1): op = operators[index1[n, 1]] # if the coefficient is too small, ignore its contribution if abs(coeff1[n]) > tol and np.linalg.norm(op.reshape(1, -1)) > tol: v_left, v_middle, v_right = self.environment_s1( p, op, index1[n, 0]) if self._debug: self.check_environments(v_left, v_middle, v_right, p) tensor1 -= tau * coeff1[n] * T_module.absorb_matrices2tensor( tensor, [v_left, v_middle, v_right]) nh2 = index2.shape[0] # number of two-body Hamiltonians for n in range(0, nh2): # if the coefficient is too small, ignore its contribution if abs(coeff2[n]) > tol: op = [operators[index2[n, 2]], operators[index2[n, 3]]] v_left, v_middle, v_right = self.environment_s1_s2( p, op, index2[n, :2]) if self._debug: self.check_environments(v_left, v_middle, v_right, p) tensor1 -= tau * coeff2[n] * T_module.absorb_matrices2tensor( tensor, [v_left, v_middle, v_right]) return tensor1.reshape(-1, 1)
def effective_hamiltonian_dmrg(self, p, operators, index1, index2, coeff1, coeff2, tol=1e-12): if self._debug and p != self.center: print_error( 'CenterError: the tensor must be at the orthogonal center before ' 'defining the function handle', 'magenta') nh1 = index1.shape[0] s = [self.virtual_dim[p], self.phys_dim, self.virtual_dim[p + 1]] dim = np.prod(s) h_effect = np.zeros((dim, dim)) for n in range(0, nh1): # if the coefficient is too small, ignore its contribution if abs(coeff1[n]) > tol and np.linalg.norm( operators[index1[n, 1]].reshape(1, -1)) > tol: v_left, v_middle, v_right = self.environment_s1( p, operators[index1[n, 1]], index1[n, 0]) if self._debug: self.check_environments(v_left, v_middle, v_right, p) h_effect += coeff1[n] * np.kron(np.kron(v_left, v_middle), v_right) nh2 = index2.shape[0] # number of two-body Hamiltonians for n in range(0, nh2): # if the coefficient is too small, ignore its contribution if abs(coeff2[n]) > tol: v_left, v_middle, v_right = \ self.environment_s1_s2(p, [operators[index2[n, 2]], operators[index2[n, 3]]], index2[n, :2]) if self._debug: self.check_environments(v_left, v_middle, v_right, p) h_effect += coeff2[n] * np.kron(np.kron(v_left, v_middle), v_right) h_effect = (h_effect + h_effect.conj().T) / 2 return h_effect, s