Example #1
0
    def calc_K_l(self, n_low=-1, n_high=-1):
        """Generates the K matrices used to calculate the B's.
        For the left gauge-fixing case.
        """
        if n_low < 2:
            n_low = 2
        if n_high < 1:
            n_high = self.N
            
        self.K[1] = sp.zeros((self.D[1], self.D[1]), dtype=self.typ)
            
        for n in xrange(n_low, n_high + 1):
            #if n <= self.N - self.ham_sites + 1:
            if self.ham_sites == 2:
                self.K[n], ex = tm.calc_K_l(self.K[n - 1], self.C[n - 1], self.l[n - 2], 
                                            self.r[n], self.A[n], self.AA[n - 1])
            else:
                assert False, 'left gauge fixing not yet supported for three-site Hamiltonians'

            self.h_expect[n - 1] = ex
            #else:
            #    self.K[n].fill(0)
                
        if n_high == self.N:
            self.H_expect = sp.asscalar(self.K[self.N])
Example #2
0
    def calc_K_l(self, n_low=-1, n_high=-1):
        """Generates the K matrices used to calculate the B's.
        For the left gauge-fixing case.
        """
        if n_low < 2:
            n_low = 2
        if n_high < 1:
            n_high = self.N
            
        self.K[1] = sp.zeros((self.D[1], self.D[1]), dtype=self.typ)
            
        for n in xrange(n_low, n_high + 1):
            #if n <= self.N - self.ham_sites + 1:
            if self.ham_sites == 2:
                self.K[n], ex = tm.calc_K_l(self.K[n - 1], self.C[n - 1], self.l[n - 2], 
                                          self.r[n], self.A[n], self.A[n - 1], 
                                          sanity_checks=self.sanity_checks)
            else:
                assert False, 'left gauge fixing not yet supported for three-site Hamiltonians'

            self.h_expect[n - 1] = ex
            #else:
            #    self.K[n].fill(0)
                
        if n_high == self.N:
            self.H_expect = sp.asscalar(self.K[self.N])
Example #3
0
    def calc_K(self):
        """Generates the right K matrices used to calculate the B's
        
        K[n] contains 'column-vectors' such that <l[n]|K[n]> = trace(l[n].dot(K[n])).
        K_l[n] contains 'bra-vectors' such that <K_l[n]|r[n]> = trace(K_l[n].dot(r[n])).
        """
   
        self.h_expect = sp.zeros((self.N + 1), dtype=self.typ)
        
        self.uni_r.calc_AA()
        self.uni_r.calc_C()
        self.uni_r.calc_K()
        self.K[self.N + 1][:] = self.uni_r.K[0]

        self.uni_l.calc_AA()
        self.uni_l.calc_C()
        K_left, h_left_uni = self.uni_l.calc_K_l()
        
        self.K_l[0][:] = K_left[-1]

        for n in xrange(self.N, self.N_centre - 1, -1):
            self.K[n], he = tm.calc_K(self.K[n + 1], self.C[n], self.get_l(n - 1),
                                      self.r[n + 1], self.A[n], self.get_AA(n))
                
            self.h_expect[n] = he

        for n in xrange(1, self.N_centre + 1):
            self.K_l[n], he = tm.calc_K_l(self.K_l[n - 1], self.C[n - 1], self.get_l(n - 2),
                                          self.r[n], self.A[n], self.get_AA(n - 1))
                
            self.h_expect[n - 1] = he

        self.dH_expect = (mm.adot_noconj(self.K_l[self.N_centre], self.r[self.N_centre]) 
                          + mm.adot(self.l[self.N_centre - 1], self.K[self.N_centre]) 
                          - (self.N + 1) * self.uni_r.h_expect)
Example #4
0
    def calc_K(self):
        """Generates the right K matrices used to calculate the B's
        
        K[n] contains 'column-vectors' such that <l[n]|K[n]> = trace(l[n].dot(K[n])).
        K_l[n] contains 'bra-vectors' such that <K_l[n]|r[n]> = trace(K_l[n].dot(r[n])).
        """

        self.h_expect = sp.zeros((self.N + 1), dtype=self.typ)

        self.uni_r.calc_AA()
        self.uni_r.calc_C()
        self.uni_r.calc_K()
        self.K[self.N + 1][:] = self.uni_r.K

        self.uni_l.calc_AA()
        self.uni_l.calc_C()
        K_left, h_left_uni = self.uni_l.calc_K_l()
        self.K_l[0][:] = K_left

        for n in xrange(self.N, self.N_centre - 1, -1):
            self.K[n], he = tm.calc_K(self.K[n + 1],
                                      self.C[n],
                                      self.get_l(n - 1),
                                      self.r[n + 1],
                                      self.A[n],
                                      self.A[n + 1],
                                      sanity_checks=self.sanity_checks)

            self.h_expect[n] = he

        for n in xrange(1, self.N_centre + 1):
            self.K_l[n], he = tm.calc_K_l(self.K_l[n - 1],
                                          self.C[n - 1],
                                          self.get_l(n - 2),
                                          self.r[n],
                                          self.A[n],
                                          self.A[n - 1],
                                          sanity_checks=self.sanity_checks)

            self.h_expect[n - 1] = he

        self.dH_expect = (
            mm.adot_noconj(self.K_l[self.N_centre], self.r[self.N_centre]) +
            mm.adot(self.l[self.N_centre - 1], self.K[self.N_centre]) -
            (self.N + 1) * self.uni_r.h_expect)
Example #5
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 #6
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])