Пример #1
0
    def update_LR(self, lr_group, isite):
        first_LR, second_LR, third_LR, forth_LR = lr_group
        cv_isite = self.cv_mpo[isite - 1]
        dag_cv_isite = moveaxis(cv_isite, (1, 2), (2, 1))
        if self.method == "1site":
            if not self.cv_mpo.to_right:
                path1 = [([0, 1], "abcd, efga -> bcdefg"),
                         ([3, 0], "bcdefg, hgib -> cdefhi"),
                         ([2, 0], "cdefhi, jikc -> defhjk"),
                         ([1, 0], "defhjk, lkfd -> ehjl")]
                path2 = [([0, 1], "ab, cdea->bcde"), ([1,
                                                       0], "bcde, fedb->cf")]
                first_LR[isite - 1] = multi_tensor_contract(
                    path1, first_LR[isite], dag_cv_isite,
                    self.a_oper[isite - 1], self.a_oper[isite - 1], cv_isite)
                second_LR[isite - 1] = multi_tensor_contract(
                    path1, second_LR[isite], dag_cv_isite,
                    self.a_oper[isite - 1], cv_isite, self.h_mpo[isite - 1])
                third_LR[isite - 1] = multi_tensor_contract(
                    path1, third_LR[isite], self.h_mpo[isite - 1],
                    dag_cv_isite, cv_isite, self.h_mpo[isite - 1])
                forth_LR[isite - 1] = multi_tensor_contract(
                    path2, forth_LR[isite],
                    moveaxis(self.b_mpo[isite - 1], (1, 2), (2, 1)), cv_isite)

            else:
                path1 = [([0, 1], "abcd, aefg -> bcdefg"),
                         ([3, 0], "bcdefg, bfhi -> cdeghi"),
                         ([2, 0], "cdeghi, chjk -> degijk"),
                         ([1, 0], "degijk, djel -> gikl")]
                path2 = [([0, 1], "ab, acde->bcde"), ([1,
                                                       0], "bcde, bdcf->ef")]

                first_LR[isite] = multi_tensor_contract(
                    path1, first_LR[isite - 1], dag_cv_isite,
                    self.a_oper[isite - 1], self.a_oper[isite - 1], cv_isite)

                second_LR[isite] = multi_tensor_contract(
                    path1, second_LR[isite - 1], dag_cv_isite,
                    self.a_oper[isite - 1], cv_isite, self.h_mpo[isite - 1])
                third_LR[isite] = multi_tensor_contract(
                    path1, third_LR[isite - 1], self.h_mpo[isite - 1],
                    dag_cv_isite, cv_isite, self.h_mpo[isite - 1])
                forth_LR[isite] = multi_tensor_contract(
                    path2, forth_LR[isite - 1],
                    moveaxis(self.b_mpo[isite - 1], (1, 2), (2, 1)), cv_isite)
        else:
            # 2site for finite temperature is too expensive, so I drop it
            # (at least for now)
            raise NotImplementedError

        return first_LR, second_LR, third_LR, forth_LR
Пример #2
0
def renormalization_svd(cstruct,
                        qnbigl,
                        qnbigr,
                        domain,
                        nexciton,
                        Mmax,
                        percent=0):
    """
        get the new mps, mpsdim, mpdqn, complementary mps to get the next guess
        with singular value decomposition method (1 root)
    """
    assert domain in ["R", "L"]

    Uset, SUset, qnlnew, Vset, SVset, qnrnew = svd_qn.Csvd(cstruct,
                                                           qnbigl,
                                                           qnbigr,
                                                           nexciton,
                                                           system=domain)
    if domain == "R":
        mps, mpsdim, mpsqn, compmps = updatemps(Vset,
                                                SVset,
                                                qnrnew,
                                                Uset,
                                                nexciton,
                                                Mmax,
                                                percent=percent)
        return (
            moveaxis(mps.reshape(list(qnbigr.shape) + [mpsdim]), -1, 0),
            mpsdim,
            mpsqn,
            compmps.reshape(list(qnbigl.shape) + [mpsdim]),
        )
    else:
        mps, mpsdim, mpsqn, compmps = updatemps(Uset,
                                                SUset,
                                                qnlnew,
                                                Vset,
                                                nexciton,
                                                Mmax,
                                                percent=percent)
        return (
            mps.reshape(list(qnbigl.shape) + [mpsdim]),
            mpsdim,
            mpsqn,
            moveaxis(compmps.reshape(list(qnbigr.shape) + [mpsdim]), -1, 0),
        )
Пример #3
0
 def conj_trans(self):
     new_mpo = self.metacopy()
     for i in range(new_mpo.site_num):
         new_mpo[i] = moveaxis(self[i], (1, 2), (2, 1)).conj()
     new_mpo.qn = [[-i for i in mt_qn] for mt_qn in new_mpo.qn]
     return new_mpo
Пример #4
0
def renormalization_ddm(cstruct,
                        qnbigl,
                        qnbigr,
                        domain,
                        nexciton,
                        Mmax,
                        percent=0):
    """
        get the new mps, mpsdim, mpdqn, complementary mps to get the next guess
        with diagonalize reduced density matrix method (> 1 root)
    """
    nroots = len(cstruct)
    ddm = 0.0
    for iroot in range(nroots):
        if domain == "R":
            ddm += np.tensordot(
                cstruct[iroot],
                cstruct[iroot],
                axes=(range(qnbigl.ndim), range(qnbigl.ndim)),
            )
        else:
            ddm += np.tensordot(
                cstruct[iroot],
                cstruct[iroot],
                axes=(
                    range(qnbigl.ndim, cstruct[0].ndim),
                    range(qnbigl.ndim, cstruct[0].ndim),
                ),
            )
    ddm /= float(nroots)
    if domain == "L":
        Uset, Sset, qnnew = svd_qn.Csvd(ddm,
                                        qnbigl,
                                        qnbigl,
                                        nexciton,
                                        ddm=True)
    else:
        Uset, Sset, qnnew = svd_qn.Csvd(ddm,
                                        qnbigr,
                                        qnbigr,
                                        nexciton,
                                        ddm=True)
    mps, mpsdim, mpsqn, compmps = updatemps(Uset,
                                            Sset,
                                            qnnew,
                                            None,
                                            nexciton,
                                            Mmax,
                                            percent=percent)

    if domain == "R":
        return (
            moveaxis(mps.reshape(list(qnbigr.shape) + [mpsdim]), -1, 0),
            mpsdim,
            mpsqn,
            tensordot(
                Matrix(cstruct[0]),
                mps.reshape(list(qnbigr.shape) + [mpsdim]),
                axes=(range(qnbigl.ndim, cstruct[0].ndim), range(qnbigr.ndim)),
            ),
        )
    else:
        return (
            mps.reshape(list(qnbigl.shape) + [mpsdim]),
            mpsdim,
            mpsqn,
            tensordot(
                mps.reshape(list(qnbigl.shape) + [mpsdim]),
                Matrix(cstruct[0]),
                axes=(range(qnbigl.ndim), range(qnbigl.ndim)),
            ),
        )
Пример #5
0
    def update_LR(self, lr_group, direction, isite):
        first_LR, second_LR, third_LR, forth_LR = lr_group
        assert direction in ["left", "right"]
        if self.method == "1site":
            if direction == "left":
                path1 = [([0, 1], "abc, defa -> bcdef"),
                         ([2, 0], "bcdef, gfhb -> cdegh"),
                         ([1, 0], "cdegh, ihec -> dgi")]
                first_LR[isite - 1] = multi_tensor_contract(
                    path1, first_LR[isite],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                    self.a_oper[isite - 1], self.cv_mpo[isite - 1])
                path2 = [([0, 1], "abcd, efga -> bcdefg"),
                         ([3, 0], "bcdefg, hgib -> cdefhi"),
                         ([2, 0], "cdefhi, jikc -> defhjk"),
                         ([1, 0], "defhjk, lkfd -> ehjl")]
                path4 = [([0, 1], "ab, cdea->bcde"), ([1,
                                                       0], "bcde, fedb->cf")]
                second_LR[isite - 1] = multi_tensor_contract(
                    path2, second_LR[isite],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2),
                             (2, 1)), self.b_oper[isite - 1],
                    self.cv_mpo[isite - 1], self.h_mpo[isite - 1])
                third_LR[isite - 1] = multi_tensor_contract(
                    path2, third_LR[isite], self.h_mpo[isite - 1],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                    self.cv_mpo[isite - 1], self.h_mpo[isite - 1])
                forth_LR[isite - 1] = multi_tensor_contract(
                    path4, forth_LR[isite],
                    moveaxis(self.a_ket_mpo[isite - 1], (1, 2), (2, 1)),
                    self.cv_mpo[isite - 1])

            elif direction == "right":
                path1 = [([0, 1], "abc, adef -> bcdef"),
                         ([2, 0], "bcdef, begh -> cdfgh"),
                         ([1, 0], "cdfgh, cgdi -> fhi")]
                first_LR[isite] = multi_tensor_contract(
                    path1, first_LR[isite - 1],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                    self.a_oper[isite - 1], self.cv_mpo[isite - 1])
                path2 = [([0, 1], "abcd, aefg -> bcdefg"),
                         ([3, 0], "bcdefg, bfhi -> cdeghi"),
                         ([2, 0], "cdeghi, chjk -> degijk"),
                         ([1, 0], "degijk, djel -> gikl")]
                path4 = [([0, 1], "ab, acde->bcde"), ([1,
                                                       0], "bcde, bdcf->ef")]
                second_LR[isite] = multi_tensor_contract(
                    path2, second_LR[isite - 1],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2),
                             (2, 1)), self.b_oper[isite - 1],
                    self.cv_mpo[isite - 1], self.h_mpo[isite - 1])
                third_LR[isite] = multi_tensor_contract(
                    path2, third_LR[isite - 1], self.h_mpo[isite - 1],
                    moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                    self.cv_mpo[isite - 1], self.h_mpo[isite - 1])
                forth_LR[isite] = multi_tensor_contract(
                    path4, forth_LR[isite - 1],
                    moveaxis(self.a_ket_mpo[isite - 1], (1, 2), (2, 1)),
                    self.cv_mpo[isite - 1])
        else:
            # 2site for finite temperature is too expensive, so I drop it
            # (at least for now)
            raise NotImplementedError

        return first_LR, second_LR, third_LR, forth_LR
Пример #6
0
    def initialize_LR(self, direction):

        first_LR = [np.ones((1, 1, 1))]
        second_LR = [np.ones((1, 1, 1, 1))]
        forth_LR = [np.ones((1, 1))]
        for isite in range(1, len(self.cv_mpo)):
            first_LR.append(None)
            second_LR.append(None)
            forth_LR.append(None)
        first_LR.append(np.ones((1, 1, 1)))
        second_LR.append(np.ones((1, 1, 1, 1)))
        third_LR = copy.deepcopy(second_LR)
        forth_LR.append(np.ones((1, 1)))

        if direction == "right":
            for isite in range(len(self.cv_mpo), 1, -1):
                path1 = [([0, 1], "abc, defa -> bcdef"),
                         ([2, 0], "bcdef, gfhb -> cdegh"),
                         ([1, 0], "cdegh, ihec -> dgi")]
                first_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(
                        path1, first_LR[isite],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                        self.a_oper[isite - 1], self.cv_mpo[isite - 1]))
                path2 = [([0, 1], "abcd, efga -> bcdefg"),
                         ([3, 0], "bcdefg, hgib -> cdefhi"),
                         ([2, 0], "cdefhi, jikc -> defhjk"),
                         ([1, 0], "defhjk, lkfd -> ehjl")]
                path4 = [([0, 1], "ab, cdea->bcde"), ([1,
                                                       0], "bcde, fedb->cf")]
                second_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(
                        path2, second_LR[isite],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2),
                                 (2, 1)), self.b_oper[isite - 1],
                        self.cv_mpo[isite - 1], self.h_mpo[isite - 1]))
                third_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(
                        path2, third_LR[isite], self.h_mpo[isite - 1],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                        self.cv_mpo[isite - 1], self.h_mpo[isite - 1]))
                forth_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(
                        path4, forth_LR[isite],
                        moveaxis(self.a_ket_mpo[isite - 1], (1, 2), (2, 1)),
                        self.cv_mpo[isite - 1]))

        if direction == "left":

            for isite in range(1, len(self.cv_mpo)):
                path1 = [([0, 1], "abc, adef -> bcdef"),
                         ([2, 0], "bcdef, begh -> cdfgh"),
                         ([1, 0], "cdfgh, cgdi -> fhi")]
                first_LR[isite] = asnumpy(
                    multi_tensor_contract(
                        path1, first_LR[isite - 1],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                        self.a_oper[isite - 1], self.cv_mpo[isite - 1]))
                path2 = [([0, 1], "abcd, aefg -> bcdefg"),
                         ([3, 0], "bcdefg, bfhi -> cdeghi"),
                         ([2, 0], "cdeghi, chjk -> degijk"),
                         ([1, 0], "degijk, djel -> gikl")]
                path4 = [([0, 1], "ab, acde->bcde"), ([1,
                                                       0], "bcde, bdcf->ef")]
                second_LR[isite] = asnumpy(
                    multi_tensor_contract(
                        path2, second_LR[isite - 1],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2),
                                 (2, 1)), self.b_oper[isite - 1],
                        self.cv_mpo[isite - 1], self.h_mpo[isite - 1]))
                third_LR[isite] = asnumpy(
                    multi_tensor_contract(
                        path2, third_LR[isite - 1], self.h_mpo[isite - 1],
                        moveaxis(self.cv_mpo[isite - 1], (1, 2), (2, 1)),
                        self.cv_mpo[isite - 1], self.h_mpo[isite - 1]))
                forth_LR[isite] = asnumpy(
                    multi_tensor_contract(
                        path4, forth_LR[isite - 1],
                        moveaxis(self.a_ket_mpo[isite - 1], (1, 2), (2, 1)),
                        self.cv_mpo[isite - 1]))
        return [first_LR, second_LR, third_LR, forth_LR]
Пример #7
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]
Пример #8
0
    def initialize_LR(self):

        first_LR = [np.ones((1, 1, 1, 1))]
        forth_LR = [np.ones((1, 1))]
        for isite in range(1, len(self.cv_mpo)):
            first_LR.append(None)
            forth_LR.append(None)
        first_LR.append(np.ones((1, 1, 1, 1)))
        second_LR = copy.deepcopy(first_LR)
        third_LR = copy.deepcopy(first_LR)
        forth_LR.append(np.ones((1, 1)))

        if self.cv_mpo.to_right:
            for isite in range(len(self.cv_mpo), 1, -1):
                cv_isite = self.cv_mpo[isite - 1]
                dag_cv_isite = moveaxis(cv_isite, (1, 2), (2, 1))
                path1 = [([0, 1], "abcd, efga -> bcdefg"),
                         ([3, 0], "bcdefg, hgib -> cdefhi"),
                         ([2, 0], "cdefhi, jikc -> defhjk"),
                         ([1, 0], "defhjk, lkfd -> ehjl")]
                path2 = [([0, 1], "ab, cdea->bcde"), ([1,
                                                       0], "bcde, fedb->cf")]
                first_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(path1, first_LR[isite], dag_cv_isite,
                                          self.a_oper[isite - 1],
                                          self.a_oper[isite - 1], cv_isite))

                second_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(path1, second_LR[isite],
                                          dag_cv_isite, self.a_oper[isite - 1],
                                          cv_isite, self.h_mpo[isite - 1]))
                third_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(path1, third_LR[isite],
                                          self.h_mpo[isite - 1], dag_cv_isite,
                                          cv_isite, self.h_mpo[isite - 1]))
                forth_LR[isite - 1] = asnumpy(
                    multi_tensor_contract(
                        path2, forth_LR[isite],
                        moveaxis(self.b_mpo[isite - 1], (1, 2), (2, 1)),
                        cv_isite))

        else:
            for isite in range(1, len(self.cv_mpo)):
                cv_isite = self.cv_mpo[isite - 1]
                dag_cv_isite = moveaxis(cv_isite, (1, 2), (2, 1))
                path1 = [([0, 1], "abcd, aefg -> bcdefg"),
                         ([3, 0], "bcdefg, bfhi -> cdeghi"),
                         ([2, 0], "cdeghi, chjk -> degijk"),
                         ([1, 0], "degijk, djel -> gikl")]
                path2 = [([0, 1], "ab, acde->bcde"), ([1,
                                                       0], "bcde, bdcf->ef")]
                first_LR[isite] = asnumpy(
                    multi_tensor_contract(path1, first_LR[isite - 1],
                                          dag_cv_isite, self.a_oper[isite - 1],
                                          self.a_oper[isite - 1], cv_isite))
                second_LR[isite] = asnumpy(
                    multi_tensor_contract(path1, second_LR[isite - 1],
                                          dag_cv_isite, self.a_oper[isite - 1],
                                          cv_isite, self.h_mpo[isite - 1]))
                third_LR[isite] = asnumpy(
                    multi_tensor_contract(path1, third_LR[isite - 1],
                                          self.h_mpo[isite - 1], dag_cv_isite,
                                          cv_isite, self.h_mpo[isite - 1]))
                forth_LR[isite] = asnumpy(
                    multi_tensor_contract(
                        path2, forth_LR[isite - 1],
                        moveaxis(self.b_mpo[isite - 1], (1, 2), (2, 1)),
                        cv_isite))
        return [first_LR, second_LR, third_LR, forth_LR]
Пример #9
0
    def optimize_cv(self, lr_group, isite, 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)
        dag_qnmat, dag_qnbigl, dag_qnbigr = self.swap(xqnmat, xqnbigl, xqnbigr)
        nonzeros = int(
            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])]

        if self.method == "1site":
            # define dot path
            path_1 = [([0, 1], "abcd, aefg -> bcdefg"),
                      ([3, 0], "bcdefg, bfhi -> cdeghi"),
                      ([2, 0], "cdeghi, chjk -> degijk"),
                      ([1, 0], "degijk, gikl -> dejl")]
            path_2 = [([0, 1], "abcd, aefg -> bcdefg"),
                      ([3, 0], "bcdefg, bfhi -> cdeghi"),
                      ([2, 0], "cdeghi, djek -> cghijk"),
                      ([1, 0], "cghijk, gilk -> chjl")]
            path_3 = [([0, 1], "ab, acde -> bcde"), ([1,
                                                      0], "bcde, ef -> bcdf")]

            vecb = multi_tensor_contract(
                path_3, forth_L, moveaxis(self.b_mpo[isite - 1], (1, 2),
                                          (2, 1)),
                forth_R)[self.condition(dag_qnmat, [down_exciton, up_exciton])]

        a_oper_isite = asxp(self.a_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('abca->abc', first_L)
        path_m1 = [([0, 1], "abc, bdef->acdef"), ([1,
                                                   0], "acdef, cegh->adfgh")]
        M1_2 = multi_tensor_contract(path_m1, M1_1, a_oper_isite, a_oper_isite)
        M1_2 = xp.einsum("abcbd->abcd", M1_2)
        M1_3 = xp.einsum('ecde->ecd', first_R)
        M1_4 = xp.einsum('ff->f', Idt)
        path_m1 = [([0, 1], "abcd,ecd->abe"), ([1, 0], "abe,f->abef")]
        pre_M1 = multi_tensor_contract(path_m1, M1_2, M1_3, M1_4)
        pre_M1 = xp.moveaxis(pre_M1, [-2, -1], [-1, -2])[self.condition(
            dag_qnmat, [down_exciton, up_exciton])]

        M2_1 = xp.einsum('aeag->aeg', second_L)
        M2_2 = xp.einsum('eccf->ecf', a_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])]

        M_x = lambda x: asnumpy(
            asxp(x) /
            (pre_M1 + 2 * pre_M2 + pre_M4 + xp.ones(nonzeros) * self.eta**2))
        pre_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))
            if self.method == "1site":

                M1 = multi_tensor_contract(path_1, first_L, dag_struct,
                                           a_oper_isite, a_oper_isite, first_R)
                M2 = multi_tensor_contract(path_2, second_L, dag_struct,
                                           a_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 + dag_struct * self.eta**2
            cout = cout[self.condition(dag_qnmat, [down_exciton, up_exciton])]
            return asnumpy(cout)

        # Matrix A
        mat_a = scipy.sparse.linalg.LinearOperator((nonzeros, nonzeros),
                                                   matvec=hop)

        x, info = scipy.sparse.linalg.cg(mat_a,
                                         asnumpy(vecb),
                                         tol=1.e-5,
                                         x0=asnumpy(guess),
                                         maxiter=500,
                                         M=pre_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:{xp.linalg.norm(vecb)}")
        l_value = xp.dot(asxp(hop(x)), asxp(x)) - 2 * xp.dot(vecb, asxp(x))

        x = self.dag2mat(xshape, x, dag_qnmat)
        if self.method == "1site":
            x = np.moveaxis(x, [1, 2], [2, 1])
        x, xdim, xqn, compx = self.x_svd(x,
                                         xqnbigl,
                                         xqnbigr,
                                         nexciton,
                                         percent=percent)

        if self.method == "1site":
            self.cv_mpo[isite - 1] = x
            if not self.cv_mpo.to_right:
                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
                    self.cv_mpo.qnidx = isite - 2
                else:
                    self.cv_mpo[isite - 1] = \
                        tensordot(compx, self.cv_mpo[isite - 1], axes=(-1, 0))
                    self.cv_mpo.qnidx = 0
            else:
                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
                    self.cv_mpo.qnidx = isite
                else:
                    self.cv_mpo[isite - 1] = \
                        tensordot(self.cv_mpo[isite - 1], compx, axes=(-1, 0))
                    self.cv_mpo.qnidx = self.cv_mpo.site_num - 1

        else:
            if not self.cv_mpo.to_right:
                self.cv_mpo[isite - 2] = compx
                self.cv_mpo[isite - 1] = x
                self.cv_mpo.qnidx = isite - 2
            else:
                self.cv_mpo[isite - 2] = x
                self.cv_mpo[isite - 1] = compx
                self.cv_mpo.qnidx = isite - 1
            self.cv_mpo.qn[isite - 1] = xqn

        return float(l_value)