Esempio n. 1
0
    def iterate(self,
                log,
                info='',
                sp=True,
                nmax=200,
                tol=10**-6,
                divisor=None,
                piechart=True):
        '''
        The two site dmrg step.

        Parameters
        ----------
        log : Log
            The log file.
        info : str, optional
            The information string passed to self.log.
        sp : logical, optional
            True for state prediction False for not.
        nmax : int, optional
            The maximum singular values to be kept.
        tol : float, optional
            The tolerance of the singular values.
        divisor : int/None, optional
            * When int, it is used as the divisor to calculated the ground state energy per site;
            * When None, the default divisor will be used to calculated the ground state energy per site.
        piechart : logical, optional
            True for showing the piechart of self.timers while False for not.
        '''
        log << '%s(%s)\n%s\n' % (info, self.ttype, self.graph)
        with self.timers.get('Preparation'):
            Ha, Hasite = self.lcontracts[self.cut - 1], self.mpo[self.cut - 1]
            Hb, Hbsite = self.rcontracts[self.cut + 1], self.mpo[self.cut]
            Oa, (La, Sa,
                 Ra) = Hasite.labels[MPO.R], self.mps[self.cut - 1].labels
            Ob, (Lb, Sb, Rb) = Hbsite.labels[MPO.L], self.mps[self.cut].labels
            assert Ra == Lb and Oa == Ob
            Lsys, sysinfo = Label.union([La, Sa],
                                        '__DMRG_ITERATE_SYS__',
                                        flow=+1 if self.mps.qnon else 0,
                                        mode=+2 if self.ttype == 'S' else +1)
            Lenv, envinfo = Label.union([Sb, Rb],
                                        '__DMRG_ITERATE_ENV__',
                                        flow=-1 if self.mps.qnon else 0,
                                        mode=+2 if self.ttype == 'S' else +1)
            subslice = QuantumNumbers.kron(
                [Lsys.qns, Lenv.qns], signs=[1, -1]).subslice(targets=(
                    self.target.zero(), )) if self.mps.qnon else slice(None)
            shape = (len(subslice),
                     len(subslice)) if self.mps.qnon else (Lsys.qns * Lenv.qns,
                                                           Lsys.qns * Lenv.qns)
            Hsys = (Ha * Hasite).transpose([Oa, La.P, Sa.P, La, Sa]).merge(
                ([La.P, Sa.P], Lsys.P.inverse, sysinfo),
                ([La, Sa], Lsys.inverse, sysinfo))
            Henv = (Hbsite * Hb).transpose([Ob, Sb.P, Rb.P, Sb, Rb]).merge(
                ([Sb.P, Rb.P], Lenv.P.inverse, envinfo),
                ([Sb, Rb], Lenv.inverse, envinfo))
            matvec = DMRGMatVec(Hsys, Henv)

            def timedmatvec(v):
                with self.timers.get('matvec'):
                    return matvec(v)

            matrix = hm.LinearOperator(shape=shape,
                                       matvec=timedmatvec,
                                       dtype=Hsys.dtype)
        with self.timers.get('Diagonalization'):
            u, s, v = self.mps[self.cut -
                               1], self.mps.Lambda, self.mps[self.cut]
            v0 = (u * s * v).merge(
                ([La, Sa], Lsys, sysinfo),
                ([Sb, Rb], Lenv, envinfo)).toarray().reshape(
                    -1)[subslice] if sp and s.norm > RZERO else None
            es, vs = hm.eigsh(matrix, which='SA', v0=v0, k=1, tol=tol * 10**-2)
            energy, Psi = es[0], vs[:, 0]
            self.info['Etotal'] = energy, '%.6f'
            self.info['Esite'] = energy / (divisor or self.nsite), '%.8f'
            self.info['nmatvec'] = matrix.count
            self.info['overlap'] = np.inf if v0 is None else np.abs(
                Psi.conjugate().dot(v0) / norm(v0) / norm(Psi)), '%.6f'
        with self.timers.get('Truncation'):
            sysantiinfo = sysinfo if self.ttype == 'S' else np.argsort(
                sysinfo) if self.mps.qnon else None
            envantiinfo = envinfo if self.ttype == 'S' else np.argsort(
                envinfo) if self.mps.qnon else None
            qns = QuantumNumbers.mono(
                self.target.zero(),
                count=len(subslice)) if self.mps.qnon else Lsys.qns * Lenv.qns
            Lgs, new = Label('__DMRG_ITERATE_GS__',
                             qns=qns), Ra.replace(qns=None)
            u, s, v, err = partitionedsvd(Tensor(Psi, labels=[Lgs]),
                                          Lsys,
                                          new,
                                          Lenv,
                                          nmax=nmax,
                                          tol=tol,
                                          ttype=self.ttype,
                                          returnerr=True)
            self.mps[self.cut - 1] = u.split((Lsys, [La, Sa], sysantiinfo))
            self.mps[self.cut] = v.split((Lenv, [Sb, Rb], envantiinfo))
            self.mps.Lambda = s
            self.setlcontract(self.cut)
            self.setrcontract(self.cut)
            self.info['nslice'] = Lgs.dim
            self.info['nbasis'] = s.shape[0]
            self.info['err'] = err, '%.1e'
        self.timers.record()
        log << 'timers of the dmrg:\n%s\n' % self.timers.tostr(Timers.ALL)
        log << 'info of the dmrg:\n%s\n\n' % self.info
        if piechart: self.timers.graph(parents=Timers.ALL)
Esempio n. 2
0
    def iterate(self, info='', sp=True, nmax=200, tol=hm.TOL, piechart=True):
        '''
        The two site dmrg step.

        Parameters
        ----------
        info : str, optional
            The information string passed to self.log.
        sp : logical, optional
            True for state prediction False for not.
        nmax : integer, optional
            The maximum singular values to be kept.
        tol : np.float64, optional
            The tolerance of the singular values.
        piechart : logical, optional
            True for showing the piechart of self.timers while False for not.
        '''
        self.log << '%s%s\n%s\n' % (self.state, info, self.graph)
        eold = self.info['Esite']
        with self.timers.get('Preparation'):
            Ha, Hb = self._Hs_['L'][self.mps.cut -
                                    1], self._Hs_['R'][self.mps.nsite -
                                                       self.mps.cut - 1]
            Hasite, Hbsite = self.mpo[self.mps.cut - 1], self.mpo[self.mps.cut]
            La, Sa, Ra = self.mps[self.mps.cut - 1].labels
            Lb, Sb, Rb = self.mps[self.mps.cut].labels
            Oa, Ob = Hasite.labels[MPO.R], Hbsite.labels[MPO.L]
            assert Ra == Lb
            if self.mps.mode == 'QN':
                sysqns, syspt = QuantumNumbers.kron(
                    [La.qns, Sa.qns], signs='++').sort(history=True)
                envqns, envpt = QuantumNumbers.kron(
                    [Sb.qns, Rb.qns], signs='-+').sort(history=True)
                sysantipt, envantipt = np.argsort(syspt), np.argsort(envpt)
                subslice = QuantumNumbers.kron(
                    [sysqns, envqns],
                    signs='+-').subslice(targets=(self.target.zero(), ))
                qns = QuantumNumbers.mono(self.target.zero(),
                                          count=len(subslice))
                self.info['nslice'] = len(subslice)
            else:
                sysqns, syspt, sysantipt = np.product([La.qns,
                                                       Sa.qns]), None, None
                envqns, envpt, envantipt = np.product([Sb.qns,
                                                       Rb.qns]), None, None
                subslice, qns = slice(None), sysqns * envqns
                self.info['nslice'] = qns
            Lpa, Spa, Spb, Rpb = La.prime, Sa.prime, Sb.prime, Rb.prime
            Lsys, Lenv, new = Label('__DMRG_TWO_SITE_STEP_SYS__',
                                    qns=sysqns), Label(
                                        '__DMRG_TWO_SITE_STEP_ENV__',
                                        qns=envqns), Ra.replace(qns=None)
            Lpsys, Lpenv = Lsys.prime, Lenv.prime
            Hsys = contract([Ha, Hasite], engine='tensordot').transpose(
                [Oa, Lpa, Spa, La, Sa]).merge(([Lpa, Spa], Lpsys, syspt),
                                              ([La, Sa], Lsys, syspt))
            Henv = contract([Hbsite, Hb], engine='tensordot').transpose(
                [Ob, Spb, Rpb, Sb, Rb]).merge(([Spb, Rpb], Lpenv, envpt),
                                              ([Sb, Rb], Lenv, envpt))
        if self.matvec == 'csr':
            with self.timers.get('Hamiltonian'):
                if isinstance(subslice, slice):
                    rcs = None
                else:
                    rcs = (np.divide(subslice, Henv.shape[1]),
                           np.mod(subslice, Henv.shape[1]),
                           np.zeros(Hsys.shape[1] * Henv.shape[1],
                                    dtype=np.int64))
                    rcs[2][subslice] = xrange(len(subslice))
                matrix = 0
                for hsys, henv in zip(Hsys, Henv):
                    with self.timers.get('kron'):
                        temp = hm.kron(hsys, henv, rcs=rcs, timers=self.timers)
                    with self.timers.get('sum'):
                        matrix += temp
                self.info['nnz'] = matrix.nnz
                self.info['nz'] = (
                    len(np.argwhere(np.abs(matrix.data) < tol)) * 100.0 /
                    matrix.nnz) if matrix.nnz > 0 else 0, '%1.1f%%'
                self.info['density'] = 1.0 * self.info['nnz'] / self.info[
                    'nslice']**2, '%.1e'
                matrix = hm.LinearOperator(shape=matrix.shape,
                                           matvec=matrix.dot,
                                           dtype=self.dtype)
        else:
            with self.timers.get('Preparation'):
                if self.mps.mode == 'QN':
                    sysod, envod = sysqns.to_ordereddict(
                    ), envqns.to_ordereddict()
                    qnpairs = [[
                        (tuple(qn), tuple(qn - oqn)) for qn in sysqns
                        if tuple(qn) in envod and tuple(qn - oqn) in sysod
                        and tuple(qn - oqn) in envod
                    ] for oqn in Oa.qns]
                    assert len(qnpairs) == len(Hsys)
                    self.cache['vecold'] = np.zeros(Hsys.shape[1] *
                                                    Henv.shape[1],
                                                    dtype=self.dtype)
                    self.cache['vecnew'] = np.zeros(
                        (Hsys.shape[1], Henv.shape[1]), dtype=self.dtype)

                    def matvec(v):
                        with self.timers.get('matvec'):
                            vec, result = self.cache['vecold'], self.cache[
                                'vecnew']
                            vec[subslice] = v
                            result[...] = 0.0
                            vec = vec.reshape((Hsys.shape[1], Henv.shape[1]))
                            for hsys, henv, pairs in zip(Hsys, Henv, qnpairs):
                                for qn1, qn2 in pairs:
                                    result[sysod[qn1], envod[qn1]] += hsys[
                                        sysod[qn1], sysod[qn2]].dot(
                                            vec[sysod[qn2], envod[qn2]]).dot(
                                                henv.T[envod[qn2], envod[qn1]])
                        return result.reshape(-1)[subslice]

                    matrix = hm.LinearOperator(shape=(len(subslice),
                                                      len(subslice)),
                                               matvec=matvec,
                                               dtype=self.dtype)
                else:

                    def matvec(v):
                        v = v.reshape((Hsys.shape[1], Henv.shape[1]))
                        result = np.zeros_like(v)
                        for hsys, henv in zip(Hsys, Henv):
                            result += hsys.dot(v).dot(henv.T)
                        return result.reshape(-1)

                    matrix = hm.LinearOperator(
                        shape=(Hsys.shape[1] * Henv.shape[1],
                               Hsys.shape[1] * Henv.shape[1]),
                        matvec=matvec,
                        dtype=self.dtype)
        with self.timers.get('Diagonalization'):
            u, s, v = self.mps[self.mps.cut -
                               1], self.mps.Lambda, self.mps[self.mps.cut]
            if sp and norm(s) > RZERO:
                v0 = np.asarray(
                    contract([u, s, v], engine='einsum').merge(
                        ([La, Sa], Lsys, syspt),
                        ([Sb, Rb], Lenv, envpt))).reshape(-1)[subslice]
            else:
                v0 = None
            es, vs = hm.eigsh(matrix, which='SA', v0=v0, k=1)
            energy, Psi = es[0], vs[:, 0]
            self.info['Etotal'] = energy, '%.6f'
            self.info['Esite'] = energy / self.mps.nsite, '%.8f'
            self.info['dE/E'] = None if eold is None else (
                norm(self.info['Esite'] - eold) /
                norm(self.info['Esite'] + eold), '%.1e')
            self.info['nmatvec'] = matrix.count
            self.info['overlap'] = np.inf if v0 is None else np.abs(
                Psi.conjugate().dot(v0) / norm(v0) / norm(Psi)), '%.6f'
        with self.timers.get('Truncation'):
            u, s, v, err = Tensor(
                Psi, labels=[Label('__DMRG_TWO_SITE_STEP__', qns=qns)
                             ]).partitioned_svd(Lsys,
                                                new,
                                                Lenv,
                                                nmax=nmax,
                                                tol=tol,
                                                return_truncation_err=True)
            self.mps[self.mps.cut - 1] = u.split((Lsys, [La, Sa], sysantipt))
            self.mps[self.mps.cut] = v.split((Lenv, [Sb, Rb], envantipt))
            self.mps.Lambda = s
            self.set_HL_(self.mps.cut - 1, tol=tol)
            self.set_HR_(self.mps.cut, tol=tol)
            self.info['nbasis'] = len(s)
            self.info['err'] = err, '%.1e'
        self.timers.record()
        self.log << 'timers of the dmrg:\n%s\n' % self.timers.tostr(Timers.ALL)
        self.log << 'info of the dmrg:\n%s\n\n' % self.info
        if piechart: self.timers.graph(parents=Timers.ALL)