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)
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)