Exemplo n.º 1
0
 def expect_2s(self, op, n, AA=None):
     """Computes the expectation value of a nearest-neighbour two-site operator.
     
     The operator should be a q[n] x q[n + 1] x q[n] x q[n + 1] array 
     such that op[s, t, u, v] = <st|op|uv> or a function of the form 
     op(s, t, u, v) = <st|op|uv>.
     
     The state must be up-to-date -- see self.update()!
     
     Parameters
     ----------
     op : ndarray or callable
         The operator array or function.
     n : int
         The leftmost site number (operator acts on n, n + 1).
         
     Returns
     -------
     expval : floating point number
         The expectation value (data type may be complex)
     """
     A = self.A[n]
     Ap1 = self.A[n + 1]
     if AA is None:
         AA = tm.calc_AA(A, Ap1)
     
     if callable(op):
         op = sp.vectorize(op, otypes=[sp.complex128])
         op = sp.fromfunction(op, (A.shape[0], Ap1.shape[0], A.shape[0], Ap1.shape[0]))
         
     C = tm.calc_C_mat_op_AA(op, AA)
     res = tm.eps_r_op_2s_C12_AA34(self.r[n + 1], C, AA)
     return m.adot(self.l[n - 1], res)
Exemplo n.º 2
0
    def expect_2s(self, op, n):
        """Computes the expectation value of a nearest-neighbour two-site operator.

        The operator should be a q[n] x q[n + 1] x q[n] x q[n + 1] array
        such that op[s, t, u, v] = <st|op|uv> or a function of the form
        op(s, t, u, v) = <st|op|uv>.

        Parameters
        ----------
        o : ndarray or callable
            The operator array or function.
        n : int
            The leftmost site number (operator acts on n, n + 1).
        """
        A = self.get_A(n)
        Ap1 = self.get_A(n + 1)
        AA = tm.calc_AA(A, Ap1)

        if callable(op):
            op = sp.vectorize(op, otypes=[sp.complex128])
            op = sp.fromfunction(op, (A.shape[0], Ap1.shape[0], A.shape[0], Ap1.shape[0]))

        C = tm.calc_C_mat_op_AA(op, AA)
        res = tm.eps_r_op_2s_C12_AA34(self.get_r(n + 1), C, AA)
        return mm.adot(self.get_l(n - 1), res)
Exemplo n.º 3
0
    def calc_C(self, n_low=-1, n_high=-1):
        """Generates the C matrices used to calculate the K's and ultimately the B's

        These are to be used on one side of the super-operator when applying the
        nearest-neighbour Hamiltonian, similarly to C in eqn. (44) of
        arXiv:1103.0936v2 [cond-mat.str-el], except being for the non-norm-preserving case.

        Makes use only of the nearest-neighbour hamiltonian, and of the A's.

        C[n] depends on A[n] and A[n + 1].
        
        This calculation can be significantly faster if h_nn is in array form.

        """
        if self.h_nn is None:
            return

        if n_low < 1:
            n_low = 0
        if n_high < 1:
            n_high = self.N + 1

        if callable(self.h_nn):
            for n in xrange(n_low, n_high):
                self.C[n] = tm.calc_C_func_op(
                    lambda s, t, u, v: self.h_nn(n, s, t, u, v), self.get_A(n),
                    self.get_A(n + 1))
        else:
            for n in xrange(n_low, n_high):
                self.AA[n] = tm.calc_AA(self.get_A(n), self.get_A(n + 1))

                self.C[n][:] = tm.calc_C_mat_op_AA(self.h_nn[n], self.AA[n])
Exemplo n.º 4
0
    def expect_2s(self, op, n):
        """Computes the expectation value of a nearest-neighbour two-site operator.

        The operator should be a q[n] x q[n + 1] x q[n] x q[n + 1] array
        such that op[s, t, u, v] = <st|op|uv> or a function of the form
        op(s, t, u, v) = <st|op|uv>.

        Parameters
        ----------
        o : ndarray or callable
            The operator array or function.
        n : int
            The leftmost site number (operator acts on n, n + 1).
        """
        A = self.get_A(n)
        Ap1 = self.get_A(n + 1)
        AA = tm.calc_AA(A, Ap1)

        if callable(op):
            op = sp.vectorize(op, otypes=[sp.complex128])
            op = sp.fromfunction(
                op, (A.shape[0], Ap1.shape[0], A.shape[0], Ap1.shape[0]))

        C = tm.calc_C_mat_op_AA(op, AA)
        res = tm.eps_r_op_2s_C12_AA34(self.get_r(n + 1), C, AA)
        return mm.adot(self.get_l(n - 1), res)
Exemplo n.º 5
0
    def expect_2s(self, op, n):
        """Computes the expectation value of a nearest-neighbour two-site operator.
        
        The operator should be a q[n] x q[n + 1] x q[n] x q[n + 1] array 
        such that op[s, t, u, v] = <st|op|uv> or a function of the form 
        op(s, t, u, v) = <st|op|uv>.
        
        The state must be up-to-date -- see self.update()!
        
        Parameters
        ----------
        op : ndarray or callable
            The operator array or function.
        n : int
            The leftmost site number (operator acts on n, n + 1).
            
        Returns
        -------
        expval : floating point number
            The expectation value (data type may be complex)
        """
        A = self.A[n]
        Ap1 = self.A[n + 1]
        AA = tm.calc_AA(A, Ap1)

        if callable(op):
            op = sp.vectorize(op, otypes=[sp.complex128])
            op = sp.fromfunction(
                op, (A.shape[0], Ap1.shape[0], A.shape[0], Ap1.shape[0]))

        C = tm.calc_C_mat_op_AA(op, AA)
        res = tm.eps_r_op_2s_C12_AA34(self.r[n + 1], C, AA)
        return m.adot(self.l[n - 1], res)
Exemplo n.º 6
0
 def expect_2s(self, op):
     """Computes the expectation value of a nearest-neighbour two-site operator.
     
     The operator should be a q x q x q x q array 
     such that op[s, t, u, v] = <st|op|uv> or a function of the form 
     op(s, t, u, v) = <st|op|uv>.
     
     The state must be up-to-date -- see self.update()!
     
     Parameters
     ----------
     op : ndarray or callable
         The operator array or function.
         
     Returns
     -------
     expval : floating point number
         The expectation value (data type may be complex)
     """
     if callable(op):
         op = np.vectorize(op, otypes=[np.complex128])
         op = np.fromfunction(op, (self.q, self.q, self.q, self.q))        
     
     C = tm.calc_C_mat_op_AA(op, self.AA)
     res = tm.eps_r_op_2s_C12_AA34(self.r, C, self.AA)
     
     return m.adot(self.l, res)
Exemplo n.º 7
0
    def calc_C(self, n_low=-1, n_high=-1):
        """Generates the C matrices used to calculate the K's and ultimately the B's

        These are to be used on one side of the super-operator when applying the
        nearest-neighbour Hamiltonian, similarly to C in eqn. (44) of
        arXiv:1103.0936v2 [cond-mat.str-el], except being for the non-norm-preserving case.

        Makes use only of the nearest-neighbour hamiltonian, and of the A's.

        C[n] depends on A[n] and A[n + 1].
        
        This calculation can be significantly faster if h_nn is in array form.

        """
        if self.h_nn is None:
            return

        if n_low < 1:
            n_low = 0
        if n_high < 1:
            n_high = self.N + 1
        
        if callable(self.h_nn):
            for n in xrange(n_low, n_high):
                self.C[n] = tm.calc_C_func_op(lambda s,t,u,v: self.h_nn(n,s,t,u,v), 
                                              self.get_A(n), self.get_A(n + 1))
        else:
            for n in xrange(n_low, n_high):                   
                self.AA[n] = tm.calc_AA(self.get_A(n), self.get_A(n + 1))
                
                self.C[n][:] = tm.calc_C_mat_op_AA(self.h_nn[n], self.AA[n])
Exemplo n.º 8
0
 def matvec(self, x):
     self.calls += 1
     #print self.calls
     
     t = self.tdvp
     n = self.n
     
     An = x.reshape((self.q[n], self.D[n - 1], self.D[n]))
     
     if n > 1:
         AAnm1 = tm.calc_AA(t.A[n - 1], An)
         Cnm1 = tm.calc_C_mat_op_AA(t.ham[n - 1], AAnm1)
     else:
         AAnm1 = None
         Cnm1 = None
         
     if n < t.N:
         AAn = tm.calc_AA(An, t.A[n + 1])
         Cn = tm.calc_C_mat_op_AA(t.ham[n], AAn)
     else:
         AAn = None
         Cn = None
     
     res = sp.zeros_like(An)
     
     #Assuming RCF        
     if not Cnm1 is None:
         for s in xrange(t.q[n]):
             res[s] += tm.eps_l_noop(t.l[n - 2], t.A[n - 1], Cnm1[:, s])
             res[s] += self.KLnm1.dot(An[s])
         res[s] = self.lm1_i.dot(res[s])
             
     if not Cn is None:
         for s in xrange(t.q[n]):                
             res[s] += tm.eps_r_noop(t.r[n + 1], Cn[s, :], t.A[n + 1])
             res[s] += An[s].dot(t.K[n + 1])
             
     #print "en = ", (sp.inner(An.conj().ravel(), res.ravel())
     #                / sp.inner(An.conj().ravel(), An.ravel()))
     
     return res.reshape(x.shape) * self.tau
Exemplo n.º 9
0
    def calc_C(self, n_low=-1, n_high=-1):
        """Generates the C tensors used to calculate the K's and ultimately the B's.
        
        This is called automatically by self.update().
        
        C[n] contains a contraction of the Hamiltonian self.ham with the parameter
        tensors over the local basis indices.
        
        This is prerequisite for calculating the tangent vector parameters B,
        which optimally approximate the exact time evolution.
        
        These are to be used on one side of the super-operator when applying the
        nearest-neighbour Hamiltonian, similarly to C in eqn. (44) of 
        arXiv:1103.0936v2 [cond-mat.str-el], for the non-norm-preserving case.

        Makes use only of the nearest-neighbour Hamiltonian, and of the A's.
        
        C[n] depends on A[n] through A[n + self.ham_sites - 1].
        
        """
        if self.ham is None:
            return 0
        
        if n_low < 1:
            n_low = 1
        if n_high < 1:
            n_high = self.N - self.ham_sites + 1
            
        for n in xrange(1, self.N):
            self.AA[n] = tm.calc_AA(self.A[n], self.A[n + 1])
        
        if self.ham_sites == 3:
            for n in xrange(1, self.N - 1):
                self.AAA[n] = tm.calc_AAA_AA(self.AA[n], self.A[n + 2])
        else:
            self.AAA.fill(None)
        
        for n in xrange(n_low, n_high + 1):
            if callable(self.ham):
                ham_n = lambda *args: self.ham(n, *args)
                ham_n = sp.vectorize(ham_n, otypes=[sp.complex128])
                ham_n = sp.fromfunction(ham_n, tuple(self.C[n].shape[:-2] * 2))
            else:
                ham_n = self.ham[n]
            
            if self.ham_sites == 2:
                self.C[n] = tm.calc_C_mat_op_AA(ham_n, self.AA[n])
            else:
                self.C[n] = tm.calc_C_3s_mat_op_AAA(ham_n, self.AAA[n])                
Exemplo n.º 10
0
    def calc_C(self, n_low=-1, n_high=-1):
        """Generates the C tensors used to calculate the K's and ultimately the B's.
        
        This is called automatically by self.update().
        
        C[n] contains a contraction of the Hamiltonian self.ham with the parameter
        tensors over the local basis indices.
        
        This is prerequisite for calculating the tangent vector parameters B,
        which optimally approximate the exact time evolution.
        
        These are to be used on one side of the super-operator when applying the
        nearest-neighbour Hamiltonian, similarly to C in eqn. (44) of 
        arXiv:1103.0936v2 [cond-mat.str-el], for the non-norm-preserving case.

        Makes use only of the nearest-neighbour Hamiltonian, and of the A's.
        
        C[n] depends on A[n] through A[n + self.ham_sites - 1].
        
        """
        if self.ham is None:
            return 0
        
        if n_low < 1:
            n_low = 1
        if n_high < 1:
            n_high = self.N - self.ham_sites + 1
        
        for n in xrange(n_low, n_high + 1):
            if callable(self.ham):
                ham_n = lambda *args: self.ham(n, *args)
                ham_n = sp.vectorize(ham_n, otypes=[sp.complex128])
                ham_n = sp.fromfunction(ham_n, tuple(self.C[n].shape[:-2] * 2))
            else:
                ham_n = self.ham[n]
                
            if self.ham_sites == 2:
                AA = tm.calc_AA(self.A[n], self.A[n + 1])
                self.C[n] = tm.calc_C_mat_op_AA(ham_n, AA)
            else:
                AAA = tm.calc_AAA(self.A[n], self.A[n + 1], self.A[n + 2])
                self.C[n] = tm.calc_C_3s_mat_op_AAA(ham_n, AAA)                
Exemplo n.º 11
0
    def matvec(self, x):
        self.calls += 1
        #print self.calls
        
        t = self.tdvp
        n = self.n
        
        Gn = x.reshape((self.D[n], self.D[n]))

        res = self.KLn.dot(Gn) + Gn.dot(t.K[n + 1])
        
        if n < t.N:
            Ap1 = sp.array([Gn.dot(As) for As in t.A[n + 1]])
            AAn = tm.calc_AA(t.A[n], Ap1)
            Cn = tm.calc_C_mat_op_AA(t.ham[n], AAn)
            for s in xrange(t.q[n]):
                sres = tm.eps_r_noop(t.r[n + 1], Cn[s, :], t.A[n + 1])
                res += t.A[n][s].conj().T.dot(t.l[n - 1].dot(sres))
        
        return res.reshape(x.shape) * self.tau
Exemplo n.º 12
0
    def calc_BHB_prereq(self, tdvp, tdvp2):
        """Calculates prerequisites for the application of the effective Hamiltonian in terms of tangent vectors.
        
        This is called (indirectly) by the self.excite.. functions.
        
        Parameters
        ----------
        tdvp2: EvoMPS_TDVP_Uniform
            Second state (may be the same, or another ground state).
            
        Returns
        -------
        A lot of stuff.
        """
        l = tdvp.l[0]
        r_ = tdvp2.r[0]
        r__sqrt = tdvp2.r_sqrt[0]
        r__sqrt_i = tdvp2.r_sqrt_i[0]
        A = tdvp.A[0]
        A_ = tdvp2.A[0]
        AA = tdvp.AA[0]
        AA_ = tdvp2.AA[0]
        AAA_ = tdvp2.AAA[0]
        
        eyed = np.eye(self.q**self.ham_sites)
        eyed = eyed.reshape(tuple([self.q] * self.ham_sites * 2))
        ham_ = self.ham - tdvp.h_expect.real * eyed
            
        V_ = sp.transpose(tdvp2.Vsh[0], axes=(0, 2, 1)).conj().copy(order='C')
        
        Vri_ = sp.zeros_like(V_)
        try:
            for s in xrange(self.q):
                Vri_[s] = r__sqrt_i.dot_left(V_[s])
        except AttributeError:
            for s in xrange(self.q):
                Vri_[s] = V_[s].dot(r__sqrt_i)

        Vr_ = sp.zeros_like(V_)            
        try:
            for s in xrange(self.q):
                Vr_[s] = r__sqrt.dot_left(V_[s])
        except AttributeError:
            for s in xrange(self.q):
                Vr_[s] = V_[s].dot(r__sqrt)
                
        Vri_A_ = tm.calc_AA(Vri_, A_)
                
        if self.ham_sites == 2:
            _C_AhlA = np.empty((self.q, self.q, A.shape[2], A.shape[2]), dtype=tdvp.typ)
            for u in xrange(self.q):
                for s in xrange(self.q):
                    _C_AhlA[u, s] = A[u].conj().T.dot(l.dot(A[s]))
            C_AhlA = sp.tensordot(ham_, _C_AhlA, ((0, 2), (0, 1)))
            C_AhlA = sp.transpose(C_AhlA, axes=(1, 0, 2, 3)).copy(order='C')
            
            _C_A_Vrh_ = tm.calc_AA(A_, sp.transpose(Vr_, axes=(0, 2, 1)).conj())
            C_A_Vrh_ = sp.tensordot(ham_, _C_A_Vrh_, ((3, 1), (0, 1)))
            C_A_Vrh_ = sp.transpose(C_A_Vrh_, axes=(1, 0, 2, 3)).copy(order='C')
            
            C_Vri_A_conj = tm.calc_C_conj_mat_op_AA(ham_, Vri_A_).copy(order='C')
    
            C_ = tm.calc_C_mat_op_AA(ham_, AA_).copy(order='C')
            C_conj = tm.calc_C_conj_mat_op_AA(ham_, AA_).copy(order='C')
            
            rhs10 = tm.eps_r_op_2s_AA12_C34(r_, AA_, C_Vri_A_conj)
            
            return C_, C_conj, V_, Vr_, Vri_, C_Vri_A_conj, C_AhlA, C_A_Vrh_, rhs10
        elif self.ham_sites == 3:
            C_Vri_AA_ = np.empty((self.q, self.q, self.q, Vri_.shape[1], A_.shape[2]), dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        C_Vri_AA_[s, t, u] = Vri_[s].dot(AA_[t, u])
            C_Vri_AA_ = sp.tensordot(ham_, C_Vri_AA_, ((3, 4, 5), (0, 1, 2))).copy(order='C')
            
            C_AAA_r_Ah_Vrih = np.empty((self.q, self.q, self.q, self.q, self.q, #FIXME: could be too memory-intensive
                                        A_.shape[1], Vri_.shape[1]), 
                                       dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        for k in xrange(self.q):
                            for j in xrange(self.q):
                                C_AAA_r_Ah_Vrih[s, t, u, k, j] = AAA_[s, t, u].dot(r_.dot(A_[k].conj().T)).dot(Vri_[j].conj().T)
            C_AAA_r_Ah_Vrih = sp.tensordot(ham_, C_AAA_r_Ah_Vrih, ((3, 4, 5, 2, 1), (0, 1, 2, 3, 4))).copy(order='C')
            
            C_AhAhlAA = np.empty((self.q, self.q, self.q, self.q,
                                  A_.shape[2], A.shape[2]), dtype=tdvp.typ)
            for t in xrange(self.q):
                for j in xrange(self.q):
                    for i in xrange(self.q):
                        for s in xrange(self.q):
                            C_AhAhlAA[j, t, i, s] = AA[i, j].conj().T.dot(l.dot(AA[s, t]))
            C_AhAhlAA = sp.tensordot(ham_, C_AhAhlAA, ((4, 1, 0, 3), (1, 0, 2, 3))).copy(order='C')
            
            C_AA_r_Ah_Vrih_ = np.empty((self.q, self.q, self.q, self.q,
                                        A_.shape[1], Vri_.shape[1]), dtype=tdvp.typ)
            for t in xrange(self.q):
                for u in xrange(self.q):
                    for k in xrange(self.q):
                        for j in xrange(self.q):
                            C_AA_r_Ah_Vrih_[u, t, k, j] = AA_[t, u].dot(r_.dot(A_[k].conj().T)).dot(Vri_[j].conj().T)
            C_AA_r_Ah_Vrih_ = sp.tensordot(ham_, C_AA_r_Ah_Vrih_, ((4, 5, 2, 1), (1, 0, 2, 3))).copy(order='C')
            
            C_AAA_Vrh_ = np.empty((self.q, self.q, self.q, self.q,
                                   A_.shape[1], Vri_.shape[1]), dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        for k in xrange(self.q):
                            C_AAA_Vrh_[s, t, u, k] = AAA_[s, t, u].dot(Vr_[k].conj().T)
            C_AAA_Vrh_ = sp.tensordot(ham_, C_AAA_Vrh_, ((3, 4, 5, 2), (0, 1, 2, 3))).copy(order='C')
            
            C_Vri_A_r_Ah_ = np.empty((self.q, self.q, self.q,
                                      A_.shape[2], Vri_.shape[1]), dtype=tdvp.typ)
            for u in xrange(self.q):
                for k in xrange(self.q):
                    for j in xrange(self.q):
                        C_Vri_A_r_Ah_[u, k, j] = Vri_[j].dot(A_[k]).dot(r_.dot(A_[u].conj().T))
            C_Vri_A_r_Ah_ = sp.tensordot(ham_.conj(), C_Vri_A_r_Ah_, ((5, 2, 1), (0, 1, 2))).copy(order='C')
            
            C_AhlAA = np.empty((self.q, self.q, self.q,
                                      A_.shape[2], A.shape[2]), dtype=tdvp.typ)
            for j in xrange(self.q):
                for i in xrange(self.q):
                    for s in xrange(self.q):
                        C_AhlAA[j, i, s] = A[s].conj().T.dot(l.dot(AA[i, j]))
            C_AhlAA_conj = sp.tensordot(ham_.conj(), C_AhlAA, ((1, 0, 3), (0, 1, 2))).copy(order='C')
            C_AhlAA = sp.tensordot(ham_, C_AhlAA, ((4, 3, 0), (0, 1, 2)))
            C_AhlAA = sp.transpose(C_AhlAA, axes=(2, 0, 1, 3, 4)).copy(order='C')
            
            C_AA_Vrh = np.empty((self.q, self.q, self.q,
                                      A_.shape[2], Vr_.shape[1]), dtype=tdvp.typ)
            for t in xrange(self.q):
                for u in xrange(self.q):
                    for k in xrange(self.q):
                        C_AA_Vrh[k, u, t] = AA_[t, u].dot(Vr_[k].conj().T)
            C_AA_Vrh = sp.tensordot(ham_, C_AA_Vrh, ((4, 5, 2), (2, 1, 0))).copy(order='C')
            
            C_ = sp.tensordot(ham_, AAA_, ((3, 4, 5), (0, 1, 2))).copy(order='C')
            
            rhs10 = tm.eps_r_op_3s_C123_AAA456(r_, AAA_, C_Vri_AA_)

            #NOTE: These C's are good as C12 or C34, but only because h is Hermitian!
            #TODO: Make this consistent with the updated 2-site case above.
            
            return V_, Vr_, Vri_, Vri_A_, C_, C_Vri_AA_, C_AAA_r_Ah_Vrih, C_AhAhlAA, C_AA_r_Ah_Vrih_, C_AAA_Vrh_, C_Vri_A_r_Ah_, C_AhlAA, C_AhlAA_conj, C_AA_Vrh, rhs10,
Exemplo n.º 13
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])
Exemplo n.º 14
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])
Exemplo n.º 15
0
    def calc_BHB_prereq(self, tdvp, tdvp2):
        """Calculates prerequisites for the application of the effective Hamiltonian in terms of tangent vectors.
        
        This is called (indirectly) by the self.excite.. functions.
        
        Parameters
        ----------
        tdvp2: EvoMPS_TDVP_Uniform
            Second state (may be the same, or another ground state).
            
        Returns
        -------
        A lot of stuff.
        """
        l = tdvp.l[0]
        r_ = tdvp2.r[0]
        r__sqrt = tdvp2.r_sqrt[0]
        r__sqrt_i = tdvp2.r_sqrt_i[0]
        A = tdvp.A[0]
        A_ = tdvp2.A[0]
        AA = tdvp.AA[0]
        AA_ = tdvp2.AA[0]
        AAA_ = tdvp2.AAA[0]

        eyed = np.eye(self.q**self.ham_sites)
        eyed = eyed.reshape(tuple([self.q] * self.ham_sites * 2))
        ham_ = self.ham - tdvp.h_expect.real * eyed

        V_ = sp.transpose(tdvp2.Vsh[0], axes=(0, 2, 1)).conj().copy(order='C')

        Vri_ = sp.zeros_like(V_)
        try:
            for s in xrange(self.q):
                Vri_[s] = r__sqrt_i.dot_left(V_[s])
        except AttributeError:
            for s in xrange(self.q):
                Vri_[s] = V_[s].dot(r__sqrt_i)

        Vr_ = sp.zeros_like(V_)
        try:
            for s in xrange(self.q):
                Vr_[s] = r__sqrt.dot_left(V_[s])
        except AttributeError:
            for s in xrange(self.q):
                Vr_[s] = V_[s].dot(r__sqrt)

        Vri_A_ = tm.calc_AA(Vri_, A_)

        if self.ham_sites == 2:
            _C_AhlA = np.empty((self.q, self.q, A.shape[2], A.shape[2]),
                               dtype=tdvp.typ)
            for u in xrange(self.q):
                for s in xrange(self.q):
                    _C_AhlA[u, s] = A[u].conj().T.dot(l.dot(A[s]))
            C_AhlA = sp.tensordot(ham_, _C_AhlA, ((0, 2), (0, 1)))
            C_AhlA = sp.transpose(C_AhlA, axes=(1, 0, 2, 3)).copy(order='C')

            _C_A_Vrh_ = tm.calc_AA(A_,
                                   sp.transpose(Vr_, axes=(0, 2, 1)).conj())
            C_A_Vrh_ = sp.tensordot(ham_, _C_A_Vrh_, ((3, 1), (0, 1)))
            C_A_Vrh_ = sp.transpose(C_A_Vrh_,
                                    axes=(1, 0, 2, 3)).copy(order='C')

            C_Vri_A_conj = tm.calc_C_conj_mat_op_AA(ham_,
                                                    Vri_A_).copy(order='C')

            C_ = tm.calc_C_mat_op_AA(ham_, AA_).copy(order='C')
            C_conj = tm.calc_C_conj_mat_op_AA(ham_, AA_).copy(order='C')

            rhs10 = tm.eps_r_op_2s_AA12_C34(r_, AA_, C_Vri_A_conj)

            return C_, C_conj, V_, Vr_, Vri_, C_Vri_A_conj, C_AhlA, C_A_Vrh_, rhs10
        elif self.ham_sites == 3:
            C_Vri_AA_ = np.empty(
                (self.q, self.q, self.q, Vri_.shape[1], A_.shape[2]),
                dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        C_Vri_AA_[s, t, u] = Vri_[s].dot(AA_[t, u])
            C_Vri_AA_ = sp.tensordot(ham_, C_Vri_AA_,
                                     ((3, 4, 5), (0, 1, 2))).copy(order='C')

            C_AAA_r_Ah_Vrih = np.empty(
                (
                    self.q,
                    self.q,
                    self.q,
                    self.q,
                    self.q,  #FIXME: could be too memory-intensive
                    A_.shape[1],
                    Vri_.shape[1]),
                dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        for k in xrange(self.q):
                            for j in xrange(self.q):
                                C_AAA_r_Ah_Vrih[s, t, u, k,
                                                j] = AAA_[s, t, u].dot(
                                                    r_.dot(
                                                        A_[k].conj().T)).dot(
                                                            Vri_[j].conj().T)
            C_AAA_r_Ah_Vrih = sp.tensordot(ham_, C_AAA_r_Ah_Vrih,
                                           ((3, 4, 5, 2, 1),
                                            (0, 1, 2, 3, 4))).copy(order='C')

            C_AhAhlAA = np.empty(
                (self.q, self.q, self.q, self.q, A_.shape[2], A.shape[2]),
                dtype=tdvp.typ)
            for t in xrange(self.q):
                for j in xrange(self.q):
                    for i in xrange(self.q):
                        for s in xrange(self.q):
                            C_AhAhlAA[j, t, i,
                                      s] = AA[i,
                                              j].conj().T.dot(l.dot(AA[s, t]))
            C_AhAhlAA = sp.tensordot(ham_, C_AhAhlAA,
                                     ((4, 1, 0, 3),
                                      (1, 0, 2, 3))).copy(order='C')

            C_AA_r_Ah_Vrih_ = np.empty(
                (self.q, self.q, self.q, self.q, A_.shape[1], Vri_.shape[1]),
                dtype=tdvp.typ)
            for t in xrange(self.q):
                for u in xrange(self.q):
                    for k in xrange(self.q):
                        for j in xrange(self.q):
                            C_AA_r_Ah_Vrih_[u, t, k, j] = AA_[t, u].dot(
                                r_.dot(A_[k].conj().T)).dot(Vri_[j].conj().T)
            C_AA_r_Ah_Vrih_ = sp.tensordot(ham_, C_AA_r_Ah_Vrih_,
                                           ((4, 5, 2, 1),
                                            (1, 0, 2, 3))).copy(order='C')

            C_AAA_Vrh_ = np.empty(
                (self.q, self.q, self.q, self.q, A_.shape[1], Vri_.shape[1]),
                dtype=tdvp.typ)
            for s in xrange(self.q):
                for t in xrange(self.q):
                    for u in xrange(self.q):
                        for k in xrange(self.q):
                            C_AAA_Vrh_[s, t, u,
                                       k] = AAA_[s, t, u].dot(Vr_[k].conj().T)
            C_AAA_Vrh_ = sp.tensordot(ham_, C_AAA_Vrh_,
                                      ((3, 4, 5, 2),
                                       (0, 1, 2, 3))).copy(order='C')

            C_Vri_A_r_Ah_ = np.empty(
                (self.q, self.q, self.q, A_.shape[2], Vri_.shape[1]),
                dtype=tdvp.typ)
            for u in xrange(self.q):
                for k in xrange(self.q):
                    for j in xrange(self.q):
                        C_Vri_A_r_Ah_[u, k, j] = Vri_[j].dot(A_[k]).dot(
                            r_.dot(A_[u].conj().T))
            C_Vri_A_r_Ah_ = sp.tensordot(ham_.conj(), C_Vri_A_r_Ah_,
                                         ((5, 2, 1),
                                          (0, 1, 2))).copy(order='C')

            C_AhlAA = np.empty(
                (self.q, self.q, self.q, A_.shape[2], A.shape[2]),
                dtype=tdvp.typ)
            for j in xrange(self.q):
                for i in xrange(self.q):
                    for s in xrange(self.q):
                        C_AhlAA[j, i, s] = A[s].conj().T.dot(l.dot(AA[i, j]))
            C_AhlAA_conj = sp.tensordot(ham_.conj(), C_AhlAA,
                                        ((1, 0, 3), (0, 1, 2))).copy(order='C')
            C_AhlAA = sp.tensordot(ham_, C_AhlAA, ((4, 3, 0), (0, 1, 2)))
            C_AhlAA = sp.transpose(C_AhlAA,
                                   axes=(2, 0, 1, 3, 4)).copy(order='C')

            C_AA_Vrh = np.empty(
                (self.q, self.q, self.q, A_.shape[2], Vr_.shape[1]),
                dtype=tdvp.typ)
            for t in xrange(self.q):
                for u in xrange(self.q):
                    for k in xrange(self.q):
                        C_AA_Vrh[k, u, t] = AA_[t, u].dot(Vr_[k].conj().T)
            C_AA_Vrh = sp.tensordot(ham_, C_AA_Vrh,
                                    ((4, 5, 2), (2, 1, 0))).copy(order='C')

            C_ = sp.tensordot(ham_, AAA_,
                              ((3, 4, 5), (0, 1, 2))).copy(order='C')

            rhs10 = tm.eps_r_op_3s_C123_AAA456(r_, AAA_, C_Vri_AA_)

            #NOTE: These C's are good as C12 or C34, but only because h is Hermitian!
            #TODO: Make this consistent with the updated 2-site case above.

            return V_, Vr_, Vri_, Vri_A_, C_, C_Vri_AA_, C_AAA_r_Ah_Vrih, C_AhAhlAA, C_AA_r_Ah_Vrih_, C_AAA_Vrh_, C_Vri_A_r_Ah_, C_AhlAA, C_AhlAA_conj, C_AA_Vrh, rhs10,