Example #1
0
 def restore_LCF(self, use_QR=True, update_r=True, diag_r=True):
     """Use a gauge-transformation to restore left canonical form.
     
     See restore_RCF.
     """
     if use_QR:
         tm.restore_LCF_l_seq(self.A, self.l, sanity_checks=self.sanity_checks,
                                  sc_data="restore_LCF_l")
     else:
         G = sp.eye(self.D[0], dtype=self.typ) #This is actually just the number 1
         for n in xrange(1, self.N + 1):
             self.l[n], G, Gi = tm.restore_LCF_l(self.A[n], self.l[n - 1], G,
                                                 zero_tol=self.zero_tol,
                                                 sanity_checks=self.sanity_checks)
     
     if self.sanity_checks:
         lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N], self.A[self.N])
         if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12):
             log.warning("Sanity Fail in restore_LCF!: l_N is bad / norm failure")
     
     if diag_r:
         tm.restore_LCF_r_seq(self.A, self.r, sanity_checks=self.sanity_checks,
                                              sc_data="restore_LCF_r")
 
         if self.sanity_checks:
             if not sp.allclose(self.r[0].A, 1, atol=1E-12, rtol=1E-12):
                 log.warning("Sanity Fail in restore_LCF!: r_0 is bad / norm failure")
                 log.warning("r_0 = %s", self.r[0].squeeze().real)
             
             for n in xrange(1, self.N + 1):
                 l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
                 if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11):
                     log.warning("Sanity Fail in restore_LCF!: l_%u is bad (off by %g)", n, la.norm(l - self.l[n]))
     elif update_r:
         self.calc_r()
Example #2
0
 def restore_LCF(self, use_QR=True, update_r=True, diag_r=True):
     """Use a gauge-transformation to restore left canonical form.
     
     See restore_RCF.
     """
     if use_QR:
         tm.restore_LCF_l_seq(self.A, self.l, sanity_checks=self.sanity_checks,
                                  sc_data="restore_LCF_l")
     else:
         G = sp.eye(self.D[0], dtype=self.typ) #This is actually just the number 1
         for n in xrange(1, self.N + 1):
             self.l[n], G, Gi = tm.restore_LCF_l(self.A[n], self.l[n - 1], G,
                                                 zero_tol=self.zero_tol,
                                                 sanity_checks=self.sanity_checks)
     
     if self.sanity_checks:
         lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N], self.A[self.N])
         if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12):
             log.warning("Sanity Fail in restore_LCF!: l_N is bad / norm failure")
     
     if diag_r:
         tm.restore_LCF_r_seq(self.A, self.r, sanity_checks=self.sanity_checks,
                                              sc_data="restore_LCF_r")
 
         if self.sanity_checks:
             if not sp.allclose(self.r[0].A, 1, atol=1E-12, rtol=1E-12):
                 log.warning("Sanity Fail in restore_LCF!: r_0 is bad / norm failure")
                 log.warning("r_0 = %s", self.r[0].squeeze().real)
             
             for n in xrange(1, self.N + 1):
                 l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
                 if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11):
                     log.warning("Sanity Fail in restore_LCF!: l_%u is bad (off by %g)", n, la.norm(l - self.l[n]))
     elif update_r:
         self.calc_r()
Example #3
0
    def take_step_split(self, dtau, ham_is_Herm=True):
        """Take a time-step dtau using the split-step integrator.
        
        This is the one-site version of a DMRG-like time integrator described
        at:
          http://arxiv.org/abs/1408.5056
        
        It has a fourth-order local error and is symmetric. It requires
        iteratively computing two matrix exponentials per site, and thus
        has less predictable CPU time requirements than the Euler or RK4 
        methods.
        
        NOTE:
        This requires the expokit extension, which is included in evoMPS but 
        must be compiled during, e.g. using setup.py to build all extensions.
        
        Parameters
        ----------
        dtau : complex
            The (imaginary or real) amount of imaginary time (tau) to step.
        ham_is_Herm : bool
            Whether the Hamiltonian is really Hermitian. If so, the lanczos
            method will be used for imaginary time evolution.
        """
        #TODO: Compute eta.
        self.eta_sq.fill(0)
        self.eta = 0
        
        assert self.canonical_form == 'right', 'take_step_split only implemented for right canonical form'
        assert self.ham_sites == 2, 'take_step_split only implemented for nearest neighbour Hamiltonians'
        dtau *= -1
        from expokit_expmv import zexpmv, zexpmvh

        if sp.iscomplex(dtau) or not ham_is_Herm:
            expmv = zexpmv
            fac = 1.j
            dtau = sp.imag(dtau)
        else:
            expmv = zexpmvh
            fac = 1
            
        norm_est = abs(self.H_expect.real)
    
        KL = [None] * (self.N + 1)
        KL[1] = sp.zeros((self.D[1], self.D[1]), dtype=self.typ)
        for n in xrange(1, self.N + 1):
            lop = Vari_Opt_Single_Site_Op(self, n, KL[n - 1], tau=fac)
            #print "Befor A", n, sp.inner(self.A[n].ravel().conj(), lop.matvec(self.A[n].ravel())).real
            An = expmv(lop, self.A[n].ravel(), dtau/2., norm_est=norm_est)            
            self.A[n] = An.reshape((self.q[n], self.D[n - 1], self.D[n]))
            self.l[n] = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
            norm = m.adot(self.l[n], self.r[n])
            self.A[n] /= sp.sqrt(norm)
            #print "After A", n, sp.inner(self.A[n].ravel().conj(), lop.matvec(self.A[n].ravel())).real, norm.real
            
            #shift centre matrix right (RCF is like having a centre "matrix" at "1")
            G = tm.restore_LCF_l_seq(self.A[n - 1:n + 1], self.l[n - 1:n + 1],
                                     sanity_checks=self.sanity_checks) 
                                     
            if n > 1:
                self.AA[n - 1] = tm.calc_AA(self.A[n - 1], self.A[n])
                self.C[n - 1] = tm.calc_C_mat_op_AA(self.ham[n - 1], self.AA[n - 1])
                KL[n], ex = tm.calc_K_l(KL[n - 1], self.C[n - 1], self.l[n - 2], 
                                        self.r[n], self.A[n], self.AA[n - 1])
                
            if n < self.N:                    
                lop2 = Vari_Opt_SC_op(self, n, KL[n], tau=fac)
                #print "Befor G", n, sp.inner(G.ravel().conj(), lop2.matvec(G.ravel())).real
                G = expmv(lop2, G.ravel(), -dtau/2., norm_est=norm_est)
                G = G.reshape((self.D[n], self.D[n]))
                norm = sp.trace(self.l[n].dot(G).dot(self.r[n].dot(G.conj().T)))
                G /= sp.sqrt(norm)
                #print "After G", n, sp.inner(G.ravel().conj(), lop2.matvec(G.ravel())).real, norm.real
                
                for s in xrange(self.q[n + 1]):
                    self.A[n + 1][s] = G.dot(self.A[n + 1][s])                
                
                self.AA[n] = tm.calc_AA(self.A[n], self.A[n + 1])
                self.C[n] = tm.calc_C_mat_op_AA(self.ham[n], self.AA[n])           
   
        for n in xrange(self.N, 0, -1):
            lop = Vari_Opt_Single_Site_Op(self, n, KL[n - 1], tau=fac, sanity_checks=self.sanity_checks)
            #print "Before A", n, sp.inner(self.A[n].ravel().conj(), lop.matvec(self.A[n].ravel())).real
            An = expmv(lop, self.A[n].ravel(), dtau/2., norm_est=norm_est)
            self.A[n] = An.reshape((self.q[n], self.D[n - 1], self.D[n]))
            self.l[n] = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
            norm = m.adot(self.l[n], self.r[n])
            self.A[n] /= sp.sqrt(norm)
            #print "After A", n, sp.inner(self.A[n].ravel().conj(), lop.matvec(self.A[n].ravel())).real, norm.real
            
            #shift centre matrix left (LCF is like having a centre "matrix" at "N")
            Gi = tm.restore_RCF_r_seq(self.A[n - 1:n + 1], self.r[n - 1:n + 1],
                                      sanity_checks=self.sanity_checks)
                                      
            if n < self.N:
                self.AA[n] = tm.calc_AA(self.A[n], self.A[n + 1])
                self.C[n] = tm.calc_C_mat_op_AA(self.ham[n], self.AA[n])                                          
                self.calc_K(n_low=n, n_high=n)
            
            if n > 1:
                lop2 = Vari_Opt_SC_op(self, n - 1, KL[n - 1], tau=fac, sanity_checks=self.sanity_checks)
                Gi = expmv(lop2, Gi.ravel(), -dtau/2., norm_est=norm_est)
                Gi = Gi.reshape((self.D[n - 1], self.D[n - 1]))
                norm = sp.trace(self.l[n - 1].dot(Gi).dot(self.r[n - 1].dot(Gi.conj().T)))
                G /= sp.sqrt(norm)
                #print "After G", n, sp.inner(Gi.ravel().conj(), lop2.matvec(Gi.ravel())).real, norm.real

                for s in xrange(self.q[n - 1]):
                    self.A[n - 1][s] = self.A[n - 1][s].dot(Gi)
            
                self.AA[n - 1] = tm.calc_AA(self.A[n - 1], self.A[n])
                self.C[n - 1] = tm.calc_C_mat_op_AA(self.ham[n - 1], self.AA[n - 1])
Example #4
0
    def vari_opt_ss_sweep(self, ncv=None):
        """Perform a DMRG-style optimizing sweep to reduce the energy.
        
        This carries out the MPS version of the one-site DMRG algorithm.
        Combined with imaginary time evolution, this can dramatically improve
        convergence speed.
        """
        assert self.canonical_form == 'right', 'vari_opt_ss_sweep only implemented for right canonical form'
    
        KL = [None] * (self.N + 1)
        KL[1] = sp.zeros((self.D[1], self.D[1]), dtype=self.typ)
        for n in xrange(1, self.N + 1):
            if n > 2:
                k = n - 1
                KL[k], ex = tm.calc_K_l(KL[k - 1], self.C[k - 1], self.l[k - 2], 
                                        self.r[k], self.A[k], self.AA[k - 1])

            lop = Vari_Opt_Single_Site_Op(self, n, KL[n - 1], sanity_checks=self.sanity_checks)
            evs, eVs = las.eigsh(lop, k=1, which='SA', v0=self.A[n].ravel(), ncv=ncv)
            
            self.A[n] = eVs[:, 0].reshape((self.q[n], self.D[n - 1], self.D[n]))
            
            #shift centre matrix right (RCF is like having a centre "matrix" at "1")
            G = tm.restore_LCF_l_seq(self.A[n - 1:n + 1], self.l[n - 1:n + 1],
                                     sanity_checks=self.sanity_checks)
            
            #This is not strictly necessary, since r[n] is not used again,
            self.r[n] = G.dot(self.r[n].dot(G.conj().T))

            if n < self.N:
                for s in xrange(self.q[n + 1]):
                    self.A[n + 1][s] = G.dot(self.A[n + 1][s])
            
            #All needed l and r should now be up to date
            #All needed KR should be valid still
            #AA and C must be updated
            if n > 1:
                self.AA[n - 1] = tm.calc_AA(self.A[n - 1], self.A[n])
                self.C[n - 1] = tm.calc_C_mat_op_AA(self.ham[n - 1], self.AA[n - 1])
            if n < self.N:
                self.AA[n] = tm.calc_AA(self.A[n], self.A[n + 1])
                self.C[n] = tm.calc_C_mat_op_AA(self.ham[n], self.AA[n])

            
        for n in xrange(self.N, 0, -1):
            if n < self.N:
                self.calc_K(n_low=n + 1, n_high=n + 1)

            lop = Vari_Opt_Single_Site_Op(self, n, KL[n - 1], sanity_checks=self.sanity_checks)
            evs, eVs = las.eigsh(lop, k=1, which='SA', v0=self.A[n].ravel(), ncv=ncv)
            
            self.A[n] = eVs[:, 0].reshape((self.q[n], self.D[n - 1], self.D[n]))
            
            #shift centre matrix left (LCF is like having a centre "matrix" at "N")
            Gi = tm.restore_RCF_r_seq(self.A[n - 1:n + 1], self.r[n - 1:n + 1],
                                      sanity_checks=self.sanity_checks)
            
            #This is not strictly necessary, since l[n - 1] is not used again
            self.l[n - 1] = Gi.conj().T.dot(self.l[n - 1].dot(Gi))

            if n > 1:
                for s in xrange(self.q[n - 1]):
                    self.A[n - 1][s] = self.A[n - 1][s].dot(Gi)
            
            #All needed l and r should now be up to date
            #All needed KL should be valid still
            #AA and C must be updated
            if n > 1:
                self.AA[n - 1] = tm.calc_AA(self.A[n - 1], self.A[n])
                self.C[n - 1] = tm.calc_C_mat_op_AA(self.ham[n - 1], self.AA[n - 1])
            if n < self.N:
                self.AA[n] = tm.calc_AA(self.A[n], self.A[n + 1])
                self.C[n] = tm.calc_C_mat_op_AA(self.ham[n], self.AA[n])