示例#1
0
    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
示例#2
0
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
示例#3
0
    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)
示例#4
0
 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)
示例#5
0
 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
示例#6
0
文件: mp.py 项目: liwt31/Renormalizer
 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
示例#7
0
    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
示例#8
0
    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)
示例#9
0
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
示例#10
0
    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)
示例#11
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
示例#12
0
    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]
示例#13
0
 def auto_corr(self):
     return np.array(self._auto_corr)
示例#14
0
 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)