def construct_X_qnmat(self, addlist): pbond = self.model.pbond_list xqnl = np.array(self.cv_mpo.qn[addlist[0]]) xqnr = np.array(self.cv_mpo.qn[addlist[-1] + 1]) xqnmat = xqnl.copy() xqnsigmalist = [] for idx in addlist: sigmaqn = self.model.basis[idx].sigmaqn xqnsigma = np.array(list(product(sigmaqn, repeat=2))) xqnsigma = xqnsigma.reshape(pbond[idx], pbond[idx], 2) xqnmat = self.qnmat_add(xqnmat, xqnsigma) xqnsigmalist.append(xqnsigma) xqnmat = self.qnmat_add(xqnmat, xqnr) matshape = list(xqnmat.shape) if self.method == "1site": if xqnmat.ndim == 4: if not self.cv_mpo.to_right: xqnmat = np.moveaxis(xqnmat.reshape(matshape + [1]), -1, -2) else: xqnmat = xqnmat.reshape([1] + matshape) if not self.cv_mpo.to_right: xqnbigl = xqnl.copy() xqnbigr = self.qnmat_add(xqnsigmalist[0], xqnr) if xqnbigr.ndim == 3: rshape = list(xqnbigr.shape) xqnbigr = np.moveaxis(xqnbigr.reshape(rshape + [1]), -1, -2) else: xqnbigl = self.qnmat_add(xqnl, xqnsigmalist[0]) xqnbigr = xqnr.copy() if xqnbigl.ndim == 3: lshape = list(xqnbigl.shape) xqnbigl = xqnbigl.reshape([1] + lshape) else: if xqnmat.ndim == 6: if addlist[0] != 0: xqnmat = np.moveaxis(xqnmat.resahpe(matshape + [1]), -1, -2) else: xqnmat = xqnmat.reshape([1] + matshape) xqnbigl = self.qnmat_add(xqnl, xqnsigmalist[0]) if xqnbigl.ndim == 3: lshape = list(xqnbigl.shape) xqnbigl = xqnbigl.reshape([1] + lshape) xqnbigr = self.qnmat_add(xqnsigmalist[-1], xqnr) if xqnbigr.ndim == 3: rshape = list(xqnbigr.shape) xqnbigr = np.moveaxis(xqnbigr.reshape(rshape + [1]), -1, -2) xshape = list(xqnmat.shape) del xshape[-1] if len(xshape) == 3: if not self.cv_mpo.to_right: xshape = xshape + [1] else: xshape = [1] + xshape return xqnmat, xqnbigl, xqnbigr, xshape
def construct_qnmat(mps, pbond, addlist, method, system): """ construct the quantum number pattern, the structure is as the coefficient QN: quantum number list at each bond pbond : physical pbond addlist : the sigma orbital set """ # print(method) assert method in ["1site", "2site"] assert system in ["L", "R"] qnl = np.array(mps.qn[addlist[0]]) qnr = np.array(mps.qn[addlist[-1] + 1]) qnmat = qnl.copy() qnsigmalist = [] for idx in addlist: qnsigma = mps[idx].sigmaqn qnmat = np.add.outer(qnmat, qnsigma) qnsigmalist.append(qnsigma) qnmat = np.add.outer(qnmat, qnr) if method == "1site": if system == "R": qnbigl = qnl qnbigr = np.add.outer(qnsigmalist[-1], qnr) else: qnbigl = np.add.outer(qnl, qnsigmalist[0]) qnbigr = qnr else: qnbigl = np.add.outer(qnl, qnsigmalist[0]) qnbigr = np.add.outer(qnsigmalist[-1], qnr) return qnmat, qnbigl, qnbigr
def auto_corr(self) -> np.ndarray: """ Correlation function :math:`C(t)`. :returns: 1-d numpy array containing the correlation function evaluated at each time step. """ return np.array(self._auto_corr)
def inter_change(ori_mat): matshape = ori_mat.shape len_mat = int(np.prod(np.array(matshape[:-1]))) ori_mat = ori_mat.reshape(len_mat, 2) change_mat = copy.deepcopy(ori_mat) change_mat[:, 0], change_mat[:, 1] = ori_mat[:, 1], ori_mat[:, 0] return change_mat.reshape(matshape)
def qnmat_add(self, mat_l, mat_r): lshape, rshape = mat_l.shape, mat_r.shape lena = int(np.prod(np.array(lshape)) / 2) lenb = int(np.prod(np.array(rshape)) / 2) matl = mat_l.reshape(lena, 2) matr = mat_r.reshape(lenb, 2) lr1 = np.add.outer(matl[:, 0], matr[:, 0]).flatten() lr2 = np.add.outer(matl[:, 1], matr[:, 1]).flatten() lr = np.zeros((len(lr1), 2)) lr[:, 0] = lr1 lr[:, 1] = lr2 shapel = list(mat_l.shape) del shapel[-1] shaper = list(mat_r.shape) del shaper[-1] lr = lr.reshape(shapel + shaper + [2]) return lr
def _get_big_qn(self, idx): assert self.qnidx == idx mt: Matrix = self[idx] sigmaqn = np.array(mt.sigmaqn) qnl = np.array(self.qn[idx]) qnr = np.array(self.qn[idx + 1]) assert qnl.size == mt.shape[0] assert qnr.size == mt.shape[-1] assert sigmaqn.size == mt.pdim_prod if self.to_right: qnbigl = np.add.outer(qnl, sigmaqn) qnbigr = qnr else: qnbigl = qnl qnbigr = np.add.outer(sigmaqn, qnr) qnmat = np.add.outer(qnbigl, qnbigr) return qnbigl, qnbigr, qnmat
def _get_big_qn(self, cidx: List[int]): r""" get the quantum number of L-block and R-block renormalized basis Parameters ---------- cidx : list a list of center(active) site index. For 1site/2site algorithm, cidx has one/two elements. Returns ------- qnbigl : np.ndarray super-L-block (L-block + active site if necessary) quantum number qnbigr : np.ndarray super-R-block (active site + R-block if necessary) quantum number qnmat : np.ndarray L-block + active site + R-block quantum number """ if len(cidx) == 2: cidx = sorted(cidx) assert cidx[0] + 1 == cidx[1] elif len(cidx) > 2: assert False assert self.qnidx in cidx sigmaqn = [np.array(self[idx].sigmaqn) for idx in cidx] qnl = np.array(self.qn[cidx[0]]) qnr = np.array(self.qn[cidx[-1] + 1]) if len(cidx) == 1: if self.to_right: qnbigl = np.add.outer(qnl, sigmaqn[0]) qnbigr = qnr else: qnbigl = qnl qnbigr = np.add.outer(sigmaqn[0], qnr) else: qnbigl = np.add.outer(qnl, sigmaqn[0]) qnbigr = np.add.outer(sigmaqn[1], qnr) qnmat = np.add.outer(qnbigl, qnbigr) return qnbigl, qnbigr, qnmat
def auto_corr_decomposition(self) -> np.ndarray: r""" Correlation function :math:`C(t)` decomposed into contributions from different parts of the current operator. Generally, the current operator can be split into two parts: current without phonon assistance and current with phonon assistance. For example, if the Holstein-Peierls model is considered: .. math:: \hat H = \sum_{mn} [\epsilon_{mn} + \sum_\lambda \hbar g_{mn\lambda} \omega_\lambda (b^\dagger_\lambda + b_\lambda) ] a^\dagger_m a_n + \sum_\lambda \hbar \omega_\lambda b^\dagger_\lambda b_\lambda Then current operator without phonon assistance is defined as: .. math:: \hat j_1 = \frac{e_0}{i\hbar} \sum_{mn} (R_m - R_n) \epsilon_{mn} a^\dagger_m a_n and the current operator with phonon assistance is defined as: .. math:: \hat j_2 = \frac{e_0}{i\hbar} \sum_{mn} (R_m - R_n) \hbar g_{mn\lambda} \omega_\lambda (b^\dagger_\lambda + b_\lambda) a^\dagger_m a_n With :math:`\hat j = \hat j_1 + \hat j_2`, the correlation function can be decomposed into four parts: .. math:: \begin{align} C(t) & = \langle \hat j(t) \hat j(0) \rangle \\ & = \langle ( \hat j_1(t) + \hat j_2(t) ) (\hat j_1(0) + \hat j_2(0) ) \rangle \\ & = \langle \hat j_1(t) \hat j_1(0) \rangle + \langle \hat j_1(t) \hat j_2(0) \rangle + \langle \hat j_2(t) \hat j_1(0) \rangle + \langle \hat j_2(t) \hat j_2(0) \rangle \end{align} :return: :math:`n \times 4` array for the decomposed correlation function defined as above where :math:`n` is the number of time steps. """ return np.array(self._auto_corr_deomposition)
def Csvd( cstruct: np.ndarray, qnbigl, qnbigr, nexciton, QR=False, system=None, full_matrices=True, ddm=False, ): """ block svd the coefficient matrix (l, sigmal, sigmar, r) or (l,sigma,r) according to the quantum number ddm is the direct diagonalization the reduced density matrix """ Gamma = cstruct.reshape((np.prod(qnbigl.shape), np.prod(qnbigr.shape))) localqnl = qnbigl.ravel() localqnr = qnbigr.ravel() Uset = [] # corresponds to nonzero svd value Uset0 = [] # corresponds to zero svd value Vset = [] Vset0 = [] Sset = [] SUset0 = [] SVset0 = [] qnlset = [] qnlset0 = [] qnrset = [] qnrset0 = [] if not ddm: # different combination if cstruct.ndim == 4: # density matrix combine = [[x, nexciton - x] for x in range(nexciton + 1)] else: min0 = min(np.min(localqnl), np.min(localqnr)) max0 = max(np.max(localqnl), np.max(localqnr)) combine = [[x, nexciton - x] for x in range(min0, max0 + 1)] else: # ddm is for diagonlize the reduced density matrix for multistate combine = [[x, x] for x in range(nexciton + 1)] for nl, nr in combine: lset = np.where(localqnl == nl)[0] rset = np.where(localqnr == nr)[0] if len(lset) == 0 or len(rset) == 0: continue # Gamma_block = Gamma[np.ix_(lset,rset)] Gamma_block = Gamma.ravel().take((lset * Gamma.shape[1]).reshape(-1, 1) + rset) if not ddm: if not QR: try: U, S, Vt = scipy.linalg.svd( Gamma_block, full_matrices=full_matrices, lapack_driver="gesdd", ) except: # print "Csvd converge failed" U, S, Vt = scipy.linalg.svd( Gamma_block, full_matrices=full_matrices, lapack_driver="gesvd", ) dim = S.shape[0] Sset.append(S) else: if full_matrices: mode = "full" else: mode = "economic" if system == "R": U, Vt = scipy.linalg.rq(Gamma_block, mode=mode) elif system == "L": U, Vt = scipy.linalg.qr(Gamma_block, mode=mode) else: assert False dim = min(Gamma_block.shape) Uset, Uset0, qnlset, qnlset0, SUset0 = blockappend( Uset, Uset0, qnlset, qnlset0, SUset0, U, nl, dim, lset, Gamma.shape[0], full_matrices=full_matrices, ) Vset, Vset0, qnrset, qnrset0, SVset0 = blockappend( Vset, Vset0, qnrset, qnrset0, SVset0, Vt.T, nr, dim, rset, Gamma.shape[1], full_matrices=full_matrices, ) else: S, U = scipy.linalg.eigh(Gamma_block) # numerical error for eigenvalue < 0 for ss in range(len(S)): if S[ss] < 0: S[ss] = 0.0 S = np.sqrt(S) dim = S.shape[0] Sset.append(S) Uset, Uset0, qnlset, qnlset0, SUset0 = blockappend( Uset, Uset0, qnlset, qnlset0, SUset0, U, nl, dim, lset, Gamma.shape[0], full_matrices=False, ) if not ddm: if full_matrices: Uset = np.concatenate(Uset + Uset0, axis=1) Vset = np.concatenate(Vset + Vset0, axis=1) qnlset = qnlset + qnlset0 qnrset = qnrset + qnrset0 if not QR: # not sorted SUset = np.concatenate(Sset + SUset0) SVset = np.concatenate(Sset + SVset0) return Uset, SUset, qnlset, Vset, SVset, qnrset else: return Uset, qnlset, Vset, qnrset else: Uset = np.concatenate(Uset, axis=1) Vset = np.concatenate(Vset, axis=1) if not QR: Sset = np.concatenate(Sset) # sort the singular value in descending order order = np.argsort(Sset)[::-1] Uset_order = Uset[:, order] Vset_order = Vset[:, order] Sset_order = Sset[order] qnlset_order = np.array(qnlset)[order].tolist() qnrset_order = np.array(qnrset)[order].tolist() return ( Uset_order, Sset_order, qnlset_order, Vset_order, Sset_order, qnrset_order, ) else: return Uset, qnlset, Vset, qnrset else: Uset = np.concatenate(Uset, axis=1) Sset = np.concatenate(Sset) return Uset, Sset, qnlset
def x_svd(self, xstruct, xqnbigl, xqnbigr, nexciton, direction, percent=0): Gamma = xstruct.reshape( np.prod(xqnbigl.shape) // 2, np.prod(xqnbigr.shape) // 2) localXqnl = xqnbigl.ravel() localXqnr = xqnbigr.ravel() list_locall = [] list_localr = [] for i in range(0, len(localXqnl), 2): list_locall.append([localXqnl[i], localXqnl[i + 1]]) for i in range(0, len(localXqnr), 2): list_localr.append([localXqnr[i], localXqnr[i + 1]]) localXqnl = copy.deepcopy(list_locall) localXqnr = copy.deepcopy(list_localr) xuset = [] xuset0 = [] xvset = [] xvset0 = [] xsset = [] xsuset0 = [] xsvset0 = [] xqnlset = [] xqnlset0 = [] xqnrset = [] xqnrset0 = [] if self.spectratype == "abs": combine = [[[y, 0], [nexciton - y, 0]] for y in range(nexciton + 1)] elif self.spectratype == "emi": combine = [[[0, y], [0, nexciton - y]] for y in range(nexciton + 1)] for nl, nr in combine: lset = np.where(self.condition(np.array(localXqnl), [nl]))[0] rset = np.where(self.condition(np.array(localXqnr), [nr]))[0] if len(lset) != 0 and len(rset) != 0: Gamma_block = Gamma.ravel().take( (lset * Gamma.shape[1]).reshape(-1, 1) + rset) try: U, S, Vt = \ scipy.linalg.svd(Gamma_block, full_matrices=True, lapack_driver='gesdd') except: U, S, Vt = \ scipy.linalg.svd(Gamma_block, full_matrices=True, lapack_driver='gesvd') dim = S.shape[0] xsset.append(S) # U part quantum number xuset.append( svd_qn.blockrecover(lset, U[:, :dim], Gamma.shape[0])) xqnlset += [nl] * dim xuset0.append( svd_qn.blockrecover(lset, U[:, dim:], Gamma.shape[0])) xqnlset0 += [nl] * (U.shape[0] - dim) xsuset0.append(np.zeros(U.shape[0] - dim)) # V part quantum number VT = Vt.T xvset.append( svd_qn.blockrecover(rset, VT[:, :dim], Gamma.shape[1])) xqnrset += [nr] * dim xvset0.append( svd_qn.blockrecover(rset, VT[:, dim:], Gamma.shape[1])) xqnrset0 += [nr] * (VT.shape[0] - dim) xsvset0.append(np.zeros(VT.shape[0] - dim)) xuset = np.concatenate(xuset + xuset0, axis=1) xvset = np.concatenate(xvset + xvset0, axis=1) xsuset = np.concatenate(xsset + xsuset0) xsvset = np.concatenate(xsset + xsvset0) xqnlset = xqnlset + xqnlset0 xqnrset = xqnrset + xqnrset0 bigl_shape = list(xqnbigl.shape) del bigl_shape[-1] bigr_shape = list(xqnbigr.shape) del bigr_shape[-1] if direction == "left": x, xdim, xqn, compx = update_cv(xvset, xsvset, xqnrset, xuset, nexciton, self.m_max, self.spectratype, percent=percent) if (self.method == "1site") and (len(bigr_shape + [xdim]) == 3): return np.moveaxis( x.reshape(bigr_shape + [1] + [xdim]), -1, 0),\ xdim, xqn, compx.reshape(bigl_shape + [xdim]) else: return np.moveaxis(x.reshape(bigr_shape + [xdim]), -1, 0),\ xdim, xqn, compx.reshape(bigl_shape + [xdim]) elif direction == "right": x, xdim, xqn, compx = update_cv(xuset, xsuset, xqnlset, xvset, nexciton, self.m_max, self.spectratype, percent=percent) if (self.method == "1site") and (len(bigl_shape + [xdim]) == 3): return x.reshape([1] + bigl_shape + [xdim]), xdim, xqn, \ np.moveaxis(compx.reshape(bigr_shape + [xdim]), -1, 0) else: return x.reshape(bigl_shape + [xdim]), xdim, xqn, \ np.moveaxis(compx.reshape(bigr_shape + [xdim]), -1, 0)
def construct_X_qnmat(self, addlist, direction): pbond = self.mol_list.pbond_list xqnl = np.array(self.cv_mpo.qn[addlist[0]]) xqnr = np.array(self.cv_mpo.qn[addlist[-1] + 1]) xqnmat = xqnl.copy() xqnsigmalist = [] for idx in addlist: if self.mol_list.ephtable.is_electron(idx): xqnsigma = np.array([[[0, 0], [0, 1]], [[1, 0], [1, 1]]]) else: xqnsigma = [] for i in range((pbond[idx])**2): xqnsigma.append([0, 0]) xqnsigma = np.array(xqnsigma) xqnsigma = xqnsigma.reshape(pbond[idx], pbond[idx], 2) xqnmat = self.qnmat_add(xqnmat, xqnsigma) xqnsigmalist.append(xqnsigma) xqnmat = self.qnmat_add(xqnmat, xqnr) matshape = list(xqnmat.shape) if self.method == "1site": if xqnmat.ndim == 4: if direction == "left": xqnmat = np.moveaxis(xqnmat.reshape(matshape + [1]), -1, -2) else: xqnmat = xqnmat.reshape([1] + matshape) if direction == "left": xqnbigl = xqnl.copy() xqnbigr = self.qnmat_add(xqnsigmalist[0], xqnr) if xqnbigr.ndim == 3: rshape = list(xqnbigr.shape) xqnbigr = np.moveaxis(xqnbigr.reshape(rshape + [1]), -1, -2) else: xqnbigl = self.qnmat_add(xqnl, xqnsigmalist[0]) xqnbigr = xqnr.copy() if xqnbigl.ndim == 3: lshape = list(xqnbigl.shape) xqnbigl = xqnbigl.reshape([1] + lshape) else: if xqnmat.ndim == 6: if addlist[0] != 0: xqnmat = np.moveaxis(xqnmat.resahpe(matshape + [1]), -1, -2) else: xqnmat = xqnmat.reshape([1] + matshape) xqnbigl = self.qnmat_add(xqnl, xqnsigmalist[0]) if xqnbigl.ndim == 3: lshape = list(xqnbigl.shape) xqnbigl = xqnbigl.reshape([1] + lshape) xqnbigr = self.qnmat_add(xqnsigmalist[-1], xqnr) if xqnbigr.ndim == 3: rshape = list(xqnbigr.shape) xqnbigr = np.moveaxis(xqnbigr.reshape(rshape + [1]), -1, -2) xshape = list(xqnmat.shape) del xshape[-1] if len(xshape) == 3: if direction == "left": xshape = xshape + [1] elif direction == "right": xshape = [1] + xshape return xqnmat, xqnbigl, xqnbigr, xshape
def optimize_cv(self, lr_group, direction, isite, num, percent=0): if self.spectratype == "abs": # quantum number restriction, |1><0| up_exciton, down_exciton = 1, 0 elif self.spectratype == "emi": # quantum number restriction, |0><1| up_exciton, down_exciton = 0, 1 nexciton = 1 first_LR, second_LR, third_LR, forth_LR = lr_group if self.method == "1site": add_list = [isite - 1] first_L = asxp(first_LR[isite - 1]) first_R = asxp(first_LR[isite]) second_L = asxp(second_LR[isite - 1]) second_R = asxp(second_LR[isite]) third_L = asxp(third_LR[isite - 1]) third_R = asxp(third_LR[isite]) forth_L = asxp(forth_LR[isite - 1]) forth_R = asxp(forth_LR[isite]) else: add_list = [isite - 2, isite - 1] first_L = asxp(first_LR[isite - 2]) first_R = asxp(first_LR[isite]) second_L = asxp(second_LR[isite - 2]) second_R = asxp(second_LR[isite]) third_L = asxp(third_LR[isite - 2]) third_R = asxp(third_LR[isite]) forth_L = asxp(forth_LR[isite - 2]) forth_R = asxp(forth_LR[isite]) xqnmat, xqnbigl, xqnbigr, xshape = \ self.construct_X_qnmat(add_list, direction) dag_qnmat, dag_qnbigl, dag_qnbigr = self.swap(xqnmat, xqnbigl, xqnbigr, direction) nonzeros = np.sum(self.condition(dag_qnmat, [down_exciton, up_exciton])) if self.method == "1site": guess = moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)) else: guess = tensordot(moveaxis(self.cv_mpo[isite - 2], (1, 2), (2, 1)), moveaxis(self.cv_mpo[isite - 1]), axes=(-1, 0)) guess = guess[self.condition(dag_qnmat, [down_exciton, up_exciton])].reshape( nonzeros, 1) if self.method == "1site": # define dot path path_1 = [([0, 1], "abc, adef -> bcdef"), ([2, 0], "bcdef, begh -> cdfgh"), ([1, 0], "cdfgh, fhi -> cdgi")] path_2 = [([0, 1], "abcd, aefg -> bcdefg"), ([3, 0], "bcdefg, bfhi -> cdeghi"), ([2, 0], "cdeghi, djek -> cghijk"), ([1, 0], "cghijk, gilk -> chjl")] path_4 = [([0, 1], "ab, acde -> bcde"), ([1, 0], "bcde, ef -> bcdf")] vecb = multi_tensor_contract( path_4, forth_L, moveaxis(self.a_ket_mpo[isite - 1], (1, 2), (2, 1)), forth_R) vecb = -self.eta * vecb a_oper_isite = asxp(self.a_oper[isite - 1]) b_oper_isite = asxp(self.b_oper[isite - 1]) h_mpo_isite = asxp(self.h_mpo[isite - 1]) # construct preconditioner Idt = xp.identity(h_mpo_isite.shape[1]) M1_1 = xp.einsum('aea->ae', first_L) M1_2 = xp.einsum('eccf->ecf', a_oper_isite) M1_3 = xp.einsum('dfd->df', first_R) M1_4 = xp.einsum('bb->b', Idt) path_m1 = [([0, 1], "ae,b->aeb"), ([2, 0], "aeb,ecf->abcf"), ([1, 0], "abcf, df->abcd")] pre_M1 = multi_tensor_contract(path_m1, M1_1, M1_4, M1_2, M1_3) pre_M1 = pre_M1[self.condition(dag_qnmat, [down_exciton, up_exciton])] M2_1 = xp.einsum('aeag->aeg', second_L) M2_2 = xp.einsum('eccf->ecf', b_oper_isite) M2_3 = xp.einsum('gbbh->gbh', h_mpo_isite) M2_4 = xp.einsum('dfdh->dfh', second_R) path_m2 = [([0, 1], "aeg,gbh->aebh"), ([2, 0], "aebh,ecf->abchf"), ([1, 0], "abhcf,dfh->abcd")] pre_M2 = multi_tensor_contract(path_m2, M2_1, M2_3, M2_2, M2_4) pre_M2 = pre_M2[self.condition(dag_qnmat, [down_exciton, up_exciton])] M4_1 = xp.einsum('faah->fah', third_L) M4_4 = xp.einsum('gddi->gdi', third_R) M4_5 = xp.einsum('cc->c', Idt) M4_path = [([0, 1], "fah,febg->ahebg"), ([2, 0], "ahebg,hjei->abgji"), ([1, 0], "abgji,gdi->abjd")] pre_M4 = multi_tensor_contract(M4_path, M4_1, h_mpo_isite, h_mpo_isite, M4_4) pre_M4 = xp.einsum('abbd->abd', pre_M4) pre_M4 = xp.tensordot(pre_M4, M4_5, axes=0) pre_M4 = xp.moveaxis(pre_M4, [2, 3], [3, 2])[self.condition( dag_qnmat, [down_exciton, up_exciton])] pre_M = (pre_M1 + 2 * pre_M2 + pre_M4) indices = np.array(range(nonzeros)) indptr = np.array(range(nonzeros + 1)) pre_M = scipy.sparse.csc_matrix((asnumpy(pre_M), indices, indptr), shape=(nonzeros, nonzeros)) M_x = lambda x: scipy.sparse.linalg.spsolve(pre_M, x) M = scipy.sparse.linalg.LinearOperator((nonzeros, nonzeros), M_x) count = 0 def hop(x): nonlocal count count += 1 dag_struct = asxp(self.dag2mat(xshape, x, dag_qnmat, direction)) if self.method == "1site": M1 = multi_tensor_contract(path_1, first_L, dag_struct, a_oper_isite, first_R) M2 = multi_tensor_contract(path_2, second_L, dag_struct, b_oper_isite, h_mpo_isite, second_R) M2 = xp.moveaxis(M2, (1, 2), (2, 1)) M3 = multi_tensor_contract(path_2, third_L, h_mpo_isite, dag_struct, h_mpo_isite, third_R) M3 = xp.moveaxis(M3, (1, 2), (2, 1)) cout = M1 + 2 * M2 + M3 cout = cout[self.condition(dag_qnmat, [down_exciton, up_exciton])].reshape( nonzeros, 1) return asnumpy(cout) # Matrix A and Vector b vecb = asnumpy(vecb)[self.condition( dag_qnmat, [down_exciton, up_exciton])].reshape(nonzeros, 1) mata = scipy.sparse.linalg.LinearOperator((nonzeros, nonzeros), matvec=hop) # conjugate gradient method # x, info = scipy.sparse.linalg.cg(MatA, VecB, atol=0) if num == 1: x, info = scipy.sparse.linalg.cg(mata, vecb, tol=1.e-5, maxiter=500, M=M, atol=0) else: x, info = scipy.sparse.linalg.cg(mata, vecb, tol=1.e-5, x0=guess, maxiter=500, M=M, atol=0) # logger.info(f"linear eq dim: {nonzeros}") # logger.info(f'times for hop:{count}') self.hop_time.append(count) if info != 0: logger.warning( f"cg not converged, vecb.norm:{np.linalg.norm(vecb)}") l_value = np.inner( hop(x).reshape(1, nonzeros), x.reshape(1, nonzeros)) - \ 2 * np.inner(vecb.reshape(1, nonzeros), x.reshape(1, nonzeros)) x = self.dag2mat(xshape, x, dag_qnmat, direction) if self.method == "1site": x = np.moveaxis(x, [1, 2], [2, 1]) x, xdim, xqn, compx = self.x_svd(x, xqnbigl, xqnbigr, nexciton, direction, percent=percent) if self.method == "1site": self.cv_mpo[isite - 1] = x if direction == "left": if isite != 1: self.cv_mpo[isite - 2] = \ tensordot(self.cv_mpo[isite - 2], compx, axes=(-1, 0)) self.cv_mpo.qn[isite - 1] = xqn else: self.cv_mpo[isite - 1] = \ tensordot(compx, self.cv_mpo[isite - 1], axes=(-1, 0)) elif direction == "right": if isite != len(self.cv_mpo): self.cv_mpo[isite] = \ tensordot(compx, self.cv_mpo[isite], axes=(-1, 0)) self.cv_mpo.qn[isite] = xqn else: self.cv_mpo[isite - 1] = \ tensordot(self.cv_mpo[isite - 1], compx, axes=(-1, 0)) else: if direction == "left": self.cv_mpo[isite - 2] = compx self.cv_mpo[isite - 1] = x else: self.cv_mpo[isite - 2] = x self.cv_mpo[isite - 1] = compx self.cv_mpo.qn[isite - 1] = xqn return l_value[0][0]
def auto_corr(self): return np.array(self._auto_corr)
def to_complex(self): # `xp.array` always creates new array, so to_complex means copy, which is # in accordance with NumPy return np.array(self.array, dtype=backend.complex_dtype)