def check_environments(self, vl, vm, vr, n): # check if the environments of the n-th tensor have consistent dimensions is_bug0 = False bond = str() if vl.shape[0] != vl.shape[1]: is_bug0 = True bond = 'LEFT' if vm.shape[0] != vm.shape[1]: is_bug0 = True bond = 'MIDDLE' if vr.shape[0] != vr.shape[1]: is_bug0 = True bond = 'RIGHT' if is_bug0: cprint( 'EnvError: for the %d-th tensor, the ' % n + bond + ' v is not square', 'magenta') is_bug = False if vl.shape[0] != self.virtual_dim[n]: is_bug = True bond = 'LEFT' if vr.shape[0] != self.virtual_dim[n + 1]: is_bug = True bond = 'RIGHT' if vm.shape[0] != self.mps[n].shape[1]: bond = 'MIDDLE' is_bug = True if is_bug: cprint( 'EnvError: for the %d-th tensor, the ' % n + bond + ' v has inconsistent dimension', 'magenta') if is_bug0 or is_bug: trace_stack()
def bound_vec_operator_right2left(tensor, op=np.zeros(0), v=np.zeros(0), normalize=False, symme=False): s = tensor.shape if op.size != 0: # deal with the operator tensor1 = absorb_matrix2tensor(tensor, op.T, 1) else: # no operator tensor1 = tensor.copy() if v.size == 0: # no input boundary vector v tensor = tensor.reshape(s[0], s[1] * s[2]).conj() tensor1 = tensor1.reshape(s[0], s[1] * s[2]) v1 = tensor.dot(tensor1.T) else: # there is an input boundary vector v if is_debug: if v.shape[0] != s[2]: cprint( 'BondDimError: the v_right has inconsistent dimension with the tensor', 'magenta') cprint('v.shape = ' + str(v.shape) + '; T.shape = ' + str(s)) trace_stack() tensor = tensor.reshape(s[0] * s[1], s[2]).conj().dot(v) v1 = tensor.reshape(s[0], s[1] * s[2]).dot( tensor1.reshape(s[0], s[1] * s[2]).T) if normalize: v1 = normalize_tensor(v1)[0] if symme: v1 = (v1 + v1.conj().T) / 2 return v1
def absorb_matrices2tensor_full_fast(tensor, mats): # generally, recommend to use the function 'absorb_matrices2tensor' # each bond will have a matrix to contract with # the matrices must be in the right order # contract the 1st bond of mat with tensor nb = tensor.ndim s = np.array(tensor.shape) is_bug = False if is_debug: for n in range(0, nb): if mats[n].shape[1] != s[n]: cprint( 'Error: the %d-th matrix has inconsistent dimension with the tensor' % n, 'magenta') cprint( 'T.shape = ' + str(s) + ', mat.shape = ' + str(mats[n].shape), 'magenta') is_bug = True for n in range(nb - 1, -1, -1): tensor = tensor.reshape(np.prod(s[:nb - 1]), s[nb - 1]).dot(mats[n]) s[-1] = mats[n].shape[1] ind = np.append(nb - 1, np.arange(0, nb - 1)) tensor = tensor.reshape(s).transpose(ind) s = s[ind] if is_debug and is_bug: trace_stack() return tensor
def check_virtual_bond_dimensions(self): is_error = False for n in range(1, self.length): if self.virtual_dim[n] != self.mps[n].shape[0] or self.virtual_dim[ n] != self.mps[n - 1].shape[2]: cprint( 'BondDimError: inconsistent dimension detected for the %d-th virtual bond' % n, 'magenta') is_error = True if is_error: trace_stack(2)
def norm_mps(self): # calculate the norm of an MPS if self._debug: lc = self.check_orthogonal_center() if lc != self.center: cprint( 'CenterError: center should be at %d but at %d' % self.center, lc, 'magenta') trace_stack() if self.center < -0.5: v = self.contract_v_l0_to_l1(0, self.length) norm = v[0, 0] else: norm = np.linalg.norm(self.mps[self.center].reshape(1, -1)) return norm
def normalize_tensor(tensor, if_flatten=False): v = tensor.reshape(-1, ) norm = np.linalg.norm(v) if norm < 1e-30: cprint('InfWarning: norm is too small to normalize', 'magenta') trace_stack() if if_flatten: return v, norm else: return tensor, norm else: if if_flatten: return v/norm, norm else: return tensor/norm, norm
def check_orthogonal_center(self, expected_center=-2, if_print=True): # Check if MPS has the correct center, or at the expected center # if not, find the correct center, or recommend a new center while it is not central orthogonal # NOTE: no central-orthogonalization in this function, only recommendation if self.center > -0.5: left = self.orthogonality[:self.center] right = self.orthogonality[self.center + 1:] if not (np.prod(left == -1) and np.prod(right == 1)): if if_print: cprint( colored('self.center is incorrect. Change it to -1', 'magenta')) trace_stack() self.center = -1 if self.center < -0.5: left = np.nonzero(self.orthogonality == -1) left = left[0][-1] right = np.nonzero(self.orthogonality == 1) right = right[0][0] if np.prod(self.orthogonality[:left + 1]) and np.prod( self.orthogonality[right:]) and left + 2 == right: self.center = left + 1 if if_print: cprint( colored('self.center is corrected to %g' % self.center, 'cyan')) else: if if_print: cprint( colored( 'MPS is not central orthogonal. self.center remains -1', 'cyan')) else: left = self.center - 1 if self.center > -0.5: if expected_center > -0.5 and expected_center != self.center: cprint('The center is at %d, not the expected position at %d' % (self.center, expected_center)) recommend_center = self.center else: # if not central-orthogonal, recommend the tensor after the last left-orthogonal one as the new center recommend_center = left + 1 return recommend_center