Пример #1
0
 def expectation(self, mpo, self_conj=None) -> float:
     if self_conj is None:
         self_conj = self._expectation_conj()
     environ = Environ()
     environ.construct(self, self_conj, mpo, "r")
     l = ones((1, 1, 1))
     r = environ.read("r", 1)
     path = self._expectation_path()
     return float(multi_tensor_contract(path, l, self[0], mpo[0], self_conj[0], r).real)
Пример #2
0
 def full_wfn(self):
     dim = np.prod(self.pbond_list)
     if 20000 < dim:
         raise ValueError("wavefunction too large")
     res = ones((1, 1, 1))
     for mt in self:
         dim1 = res.shape[1] * mt.shape[1]
         dim2 = mt.shape[-1]
         res = tensordot(res, mt, axes=1).reshape(1, dim1, dim2)
     return res[0, :, 0]
Пример #3
0
 def full_operator(self):
     dim = np.prod(self.pbond_list)
     if 20000 < dim:
         raise ValueError("operator too large")
     res = ones((1, 1, 1, 1))
     for mt in self:
         dim1 = res.shape[1] * mt.shape[1]
         dim2 = res.shape[2] * mt.shape[2]
         dim3 = mt.shape[-1]
         res = tensordot(res, mt, axes=1).transpose((0, 1, 3, 2, 4, 5)).reshape(1, dim1, dim2, dim3)
     return res[0, :, :, 0]
Пример #4
0
    def construct(self, mps, mps_conj, mpo, domain):
        tensor = ones((1, 1, 1), mps.dtype)
        assert domain in ["L", "R", "l", "r"]
        if domain == "L" or domain == "l":
            start, end, inc = 0, len(mps) - 1, 1
            self.write(domain, -1, tensor)
        else:
            start, end, inc = len(mps) - 1, 0, -1
            self.write(domain, len(mps), tensor)

        for idx in range(start, end, inc):
            tensor = self.addone(tensor, mps, mps_conj, mpo, idx, domain)
            self.write(domain, idx, tensor)
Пример #5
0
def transferMat(mps, mpsconj, domain, siteidx):
    """
    calculate the transfer matrix from the left hand or the right hand
    """
    val = ones([1, 1])
    if domain == "R":
        for imps in range(len(mps) - 1, siteidx - 1, -1):
            val = tensordot(mpsconj[imps], val, axes=(2, 0))
            val = tensordot(val, mps[imps], axes=([1, 2], [1, 2]))
    elif domain == "L":
        for imps in range(0, siteidx + 1, 1):
            val = tensordot(mpsconj[imps], val, axes=(0, 0))
            val = tensordot(val, mps[imps], axes=([0, 2], [1, 0]))

    return val
Пример #6
0
 def _calc_reduced_density_matrix(self, mp1, mp2):
     # further optimization is difficult. There are totally N^2 intermediate results to remember.
     reduced_density_matrix = np.zeros(
         (self.mol_list.mol_num, self.mol_list.mol_num), dtype=backend.complex_dtype
     )
     for i in range(self.mol_list.mol_num):
         for j in range(self.mol_list.mol_num):
             elem = ones((1, 1))
             e_idx = -1
             for mt_idx, (mt1, mt2) in enumerate(zip(mp1, mp2)):
                 if self.ephtable.is_electron(mt_idx):
                     e_idx += 1
                     axis_idx1 = int(e_idx == i)
                     axis_idx2 = int(e_idx == j)
                     sub_mt1 = mt1[:, axis_idx1, :, :]
                     sub_mt2 = mt2[:, :, axis_idx2, :]
                     elem = tensordot(elem, sub_mt1, axes=(0, 0))
                     elem = tensordot(elem, sub_mt2, axes=[(0, 1), (0, 1)])
                 else:
                     elem = tensordot(elem, mt1, axes=(0, 0))
                     elem = tensordot(elem, mt2, axes=[(0, 1, 2), (0, 2, 1)])
             reduced_density_matrix[i][j] = elem.flatten()[0]
     return reduced_density_matrix
Пример #7
0
def optimize_mps_dmrg(mps, mpo):
    """
    1 or 2 site optimization procedure
    """

    method = mps.optimize_config.method
    procedure = mps.optimize_config.procedure
    inverse = mps.optimize_config.inverse
    nroots = mps.optimize_config.nroots

    assert method in ["2site", "1site"]
    # print("optimization method", method)

    nexciton = mps.nexciton

    # construct the environment matrix
    environ = Environ()
    environ.construct(mps, mps, mpo, "L")

    nMPS = len(mps)
    # construct each sweep cycle scheme
    if method == "1site":
        loop = [["R", i]
                for i in range(nMPS - 1, -1, -1)] + [["L", i]
                                                     for i in range(0, nMPS)]
    else:
        loop = [["R", i]
                for i in range(nMPS - 1, 0, -1)] + [["L", i]
                                                    for i in range(1, nMPS)]

    # initial matrix
    ltensor = ones((1, 1, 1))
    rtensor = ones((1, 1, 1))

    energies = []
    for isweep, (mmax, percent) in enumerate(procedure):
        logger.debug(f"mmax, percent: {mmax}, {percent}")
        logger.debug(f"energy: {mps.expectation(mpo)}")
        logger.debug(f"{mps}")

        for system, imps in loop:
            if system == "R":
                lmethod, rmethod = "Enviro", "System"
            else:
                lmethod, rmethod = "System", "Enviro"

            if method == "1site":
                lsite = imps - 1
                addlist = [imps]
            else:
                lsite = imps - 2
                addlist = [imps - 1, imps]

            ltensor = environ.GetLR("L",
                                    lsite,
                                    mps,
                                    mps,
                                    mpo,
                                    itensor=ltensor,
                                    method=lmethod)
            rtensor = environ.GetLR("R",
                                    imps + 1,
                                    mps,
                                    mps,
                                    mpo,
                                    itensor=rtensor,
                                    method=rmethod)

            # get the quantum number pattern
            qnmat, qnbigl, qnbigr = construct_qnmat(mps, mpo.ephtable,
                                                    mpo.pbond_list, addlist,
                                                    method, system)
            cshape = qnmat.shape

            # hdiag
            tmp_ltensor = einsum("aba -> ba", ltensor)
            tmp_MPOimps = einsum("abbc -> abc", mpo[imps])
            tmp_rtensor = einsum("aba -> ba", rtensor)
            if method == "1site":
                #   S-a c f-S
                #   O-b-O-g-O
                #   S-a c f-S
                path = [([0, 1], "ba, bcg -> acg"), ([1, 0], "acg, gf -> acf")]
                hdiag = multi_tensor_contract(path, tmp_ltensor, tmp_MPOimps,
                                              tmp_rtensor)[(qnmat == nexciton)]
                # initial guess   b-S-c
                #                   a
                cguess = mps[imps][qnmat == nexciton]
            else:
                #   S-a c   d f-S
                #   O-b-O-e-O-g-O
                #   S-a c   d f-S
                tmp_MPOimpsm1 = einsum("abbc -> abc", mpo[imps - 1])
                path = [
                    ([0, 1], "ba, bce -> ace"),
                    ([0, 1], "edg, gf -> edf"),
                    ([0, 1], "ace, edf -> acdf"),
                ]
                hdiag = multi_tensor_contract(path, tmp_ltensor, tmp_MPOimpsm1,
                                              tmp_MPOimps,
                                              tmp_rtensor)[(qnmat == nexciton)]
                # initial guess b-S-c-S-e
                #                 a   d
                cguess = tensordot(mps[imps - 1], mps[imps],
                                   axes=1)[qnmat == nexciton]
            cguess = cguess.asnumpy()
            hdiag *= inverse
            nonzeros = np.sum(qnmat == nexciton)

            # print("Hmat dim", nonzeros)

            def hop(c):
                # convert c to initial structure according to qn pattern
                cstruct = cvec2cmat(cshape, c, qnmat, nexciton)

                if method == "1site":
                    # S-a   l-S
                    #    d
                    # O-b-O-f-O
                    #    e
                    # S-c   k-S

                    path = [
                        ([0, 1], "abc, adl -> bcdl"),
                        ([2, 0], "bcdl, bdef -> clef"),
                        ([1, 0], "clef, lfk -> cek"),
                    ]
                    cout = multi_tensor_contract(path, ltensor,
                                                 Matrix(cstruct), mpo[imps],
                                                 rtensor)
                    # for small matrices, check hermite:
                    # a=tensordot(ltensor, mpo[imps], ((1), (0)))
                    # b=tensordot(a, rtensor, ((4), (1)))
                    # c=b.transpose((0, 2, 4, 1, 3, 5))
                    # d=c.reshape(16, 16)
                else:
                    # S-a       l-S
                    #    d   g
                    # O-b-O-f-O-j-O
                    #    e   h
                    # S-c       k-S
                    path = [
                        ([0, 1], "abc, adgl -> bcdgl"),
                        ([3, 0], "bcdgl, bdef -> cglef"),
                        ([2, 0], "cglef, fghj -> clehj"),
                        ([1, 0], "clehj, ljk -> cehk"),
                    ]
                    cout = multi_tensor_contract(
                        path,
                        ltensor,
                        Matrix(cstruct),
                        mpo[imps - 1],
                        mpo[imps],
                        rtensor,
                    )
                # convert structure c to 1d according to qn
                return inverse * cout.asnumpy()[qnmat == nexciton]

            if nroots != 1:
                cguess = [cguess]
                for iroot in range(nroots - 1):
                    cguess.append(np.random.random([nonzeros]) - 0.5)

            precond = lambda x, e, *args: x / (hdiag.asnumpy() - e + 1e-4)

            e, c = davidson(hop,
                            cguess,
                            precond,
                            max_cycle=100,
                            nroots=nroots,
                            max_memory=64000)
            # scipy arpack solver : much slower than davidson
            # A = spslinalg.LinearOperator((nonzeros,nonzeros), matvec=hop)
            # e, c = spslinalg.eigsh(A,k=1, which="SA",v0=cguess)
            # print("HC loops:", count[0])
            # logger.debug(f"isweep: {isweep}, e: {e}")

            energies.append(e)

            cstruct = cvec2cmat(cshape, c, qnmat, nexciton, nroots=nroots)

            if nroots == 1:
                # direct svd the coefficient matrix
                mt, mpsdim, mpsqn, compmps = renormalization_svd(
                    cstruct,
                    qnbigl,
                    qnbigr,
                    system,
                    nexciton,
                    Mmax=mmax,
                    percent=percent,
                )
            else:
                # diagonalize the reduced density matrix
                mt, mpsdim, mpsqn, compmps = renormalization_ddm(
                    cstruct,
                    qnbigl,
                    qnbigr,
                    system,
                    nexciton,
                    Mmax=mmax,
                    percent=percent,
                )

            if method == "1site":
                mps[imps] = mt
                if system == "L":
                    if imps != len(mps) - 1:
                        mps[imps + 1] = tensordot(compmps,
                                                  mps[imps + 1],
                                                  axes=1)
                        mps.qn[imps + 1] = mpsqn
                    else:
                        mps[imps] = tensordot(mps[imps], compmps, axes=1)
                        mps.qn[imps + 1] = [0]

                else:
                    if imps != 0:
                        mps[imps - 1] = tensordot(mps[imps - 1],
                                                  compmps,
                                                  axes=1)
                        mps.qn[imps] = mpsqn
                    else:
                        mps[imps] = tensordot(compmps, mps[imps], axes=1)
                        mps.qn[imps] = [0]
            else:
                if system == "L":
                    mps[imps - 1] = mt
                    mps[imps] = compmps
                else:
                    mps[imps] = mt
                    mps[imps - 1] = compmps

                # mps.dim_list[imps] = mpsdim
                mps.qn[imps] = mpsqn

    energies = np.array(energies)
    if nroots == 1:
        logger.debug("Optimization complete, lowest energy = %g",
                     energies.min())

    return energies
Пример #8
0
# -*- coding: utf-8 -*-
# Author: Jiajun Ren <*****@*****.**>
"""
construct the operator matrix in the MPS sweep procedure
"""
from functools import reduce
from collections import deque

import numpy as np

from renormalizer.mps.matrix import Matrix, multi_tensor_contract, ones, EmptyMatrixError

sentinel = ones((1, 1, 1))


class Environ:
    def __init__(self):
        # todo: real disk and other backend
        self.virtual_disk = {}

    def construct(self, mps, mps_conj, mpo, domain):
        tensor = ones((1, 1, 1), mps.dtype)
        assert domain in ["L", "R", "l", "r"]
        if domain == "L" or domain == "l":
            start, end, inc = 0, len(mps) - 1, 1
            self.write(domain, -1, tensor)
        else:
            start, end, inc = len(mps) - 1, 0, -1
            self.write(domain, len(mps), tensor)

        for idx in range(start, end, inc):
Пример #9
0
    def _evolve_dmrg_tdvp_mctdhnew(self, mpo, evolve_dt) -> "Mps":
        # new regularization scheme
        # JCP 148, 124105 (2018)
        # JCP 149, 044119 (2018)

        # a workaround for https://github.com/scipy/scipy/issues/10164
        imag_time = np.iscomplex(evolve_dt)
        if imag_time:
            evolve_dt = -evolve_dt.imag
            # used in calculating derivatives
            coef = -1
        else:
            coef = 1j

        if self.is_left_canon:
            assert self.check_left_canonical()
            self.canonicalise()

        mps = self.to_complex(inplace=True)

        # construct the environment matrix
        environ = Environ()
        environ.construct(mps, mps.conj(), mpo, "R")

        # initial matrix
        ltensor = ones((1, 1, 1))
        rtensor = ones((1, 1, 1))

        new_mps = mps.metacopy()

        # statistics for debug output
        cmf_rk_steps = []

        for imps in range(len(mps)):
            shape = list(mps[imps].shape)

            system = "L" if mps.left else "R"
            qnbigl, qnbigr = mps._get_big_qn(imps)
            u, s, qnlset, v, s, qnrset = svd_qn.Csvd(
                mps[imps].asnumpy(),
                qnbigl,
                qnbigr,
                mps.qntot,
                system=system,
                full_matrices=False,
            )
            vt = v.T

            mps[imps] = u.reshape(shape[:-1] + [-1])

            ltensor = environ.GetLR(
                "L", imps - 1, mps, mps.conj(), mpo, itensor=ltensor, method="System"
            )
            rtensor = environ.GetLR(
                "R", imps + 1, mps, mps.conj(), mpo, itensor=rtensor, method="Enviro"
            )

            epsilon = 1e-10
            epsilon = np.sqrt(epsilon)
            s = s + epsilon * np.exp(-s / epsilon)

            svt = Matrix(np.diag(s).dot(vt))

            rtensor = tensordot(rtensor, svt, axes=(2, 1))
            rtensor = tensordot(Matrix(vt).conj(), rtensor, axes=(1, 0))

            if imps != len(mps) - 1:
                mps[imps + 1] = tensordot(svt, mps[imps + 1], axes=(-1, 0))
                mps.qn[imps + 1] = qnlset
                new_mps.qn[imps + 1] = qnlset.copy()

            S_inv = xp.diag(1.0 / s)

            hop = hop_factory(ltensor, rtensor, mpo[imps], len(shape))

            func = integrand_func_factory(shape, hop, imps == len(mps) - 1, S_inv, coef)

            sol = solve_ivp(
                func, (0, evolve_dt), mps[imps].ravel().array, method="RK45"
            )
            cmf_rk_steps.append(len(sol.t))
            ms = sol.y[:, -1].reshape(shape)

            if imps == len(mps) - 1:
                new_mps[imps] = ms * s[0]
            else:
                new_mps[imps] = ms
        mps._switch_direction()
        new_mps._switch_direction()
        new_mps.canonicalise()

        steps_stat = stats.describe(cmf_rk_steps)
        logger.debug(f"TDVP-MCTDH CMF steps: {steps_stat}")
        # new_mps.evolve_config.stat = steps_stat

        return new_mps