Ejemplo n.º 1
0
    def density_2s(self, n1, n2):
        """Returns a reduced density matrix for a pair of sites.
        
        Currently only supports sites in the nonuniform window.

        Parameters
        ----------
        n1 : int
            The site number of the first site.
        n2 : int
            The site number of the second site (must be > n1).
        """
        rho = sp.empty((self.q[n1] * self.q[n2], self.q[n1] * self.q[n2]),
                       dtype=sp.complex128)
        r_n2 = sp.empty_like(self.r[n2 - 1])
        r_n1 = sp.empty_like(self.r[n1 - 1])
        ln1m1 = self.get_l(n1 - 1)

        for s2 in xrange(self.q[n2]):
            for t2 in xrange(self.q[n2]):
                r_n2 = mm.mmul(self.A[n2][t2], self.r[n2],
                               mm.H(self.A[n2][s2]))

                r_n = r_n2
                for n in reversed(xrange(n1 + 1, n2)):
                    r_n = tm.eps_r_noop(r_n, self.A[n], self.A[n])

                for s1 in xrange(self.q[n1]):
                    for t1 in xrange(self.q[n1]):
                        r_n1 = mm.mmul(self.A[n1][t1], r_n,
                                       mm.H(self.A[n1][s1]))
                        tmp = mm.adot(ln1m1, r_n1)
                        rho[s1 * self.q[n1] + s2, t1 * self.q[n1] + t2] = tmp
        return rho
Ejemplo n.º 2
0
 def density_2s(self, d):
     """Returns a reduced density matrix for a pair of (seperated) sites.
     
     The site number basis is used: rho[s * q + u, t * q + v]
     with 0 <= s, t < q and 0 <= u, v < q.
     
     The state must be up-to-date -- see self.update()!
     
     Parameters
     ----------
     d : int
         The distance between the first and the second sites considered (d = n2 - n1).
         
     Returns
     -------
     rho : ndarray
         Reduced density matrix in the number basis.
     """
     rho = sp.empty((self.q * self.q, self.q * self.q), dtype=sp.complex128)
     
     for s2 in xrange(self.q):
         for t2 in xrange(self.q):
             r_n2 = m.mmul(self.A[t2], self.r, m.H(self.A[s2]))
             
             r_n = r_n2
             for n in xrange(d - 1):
                 r_n = tm.eps_r_noop(r_n, self.A, self.A)
                 
             for s1 in xrange(self.q):
                 for t1 in xrange(self.q):
                     r_n1 = m.mmul(self.A[t1], r_n, m.H(self.A[s1]))
                     tmp = m.adot(self.l, r_n1)
                     rho[s1 * self.q + s2, t1 * self.q + t2] = tmp
     return rho        
Ejemplo n.º 3
0
    def density_1s(self, n):
        """Returns a reduced density matrix for a single site.
        
        The site number basis is used: rho[s, t] 
        with 0 <= s, t < q[n].
        
        The state must be up-to-date -- see self.update()!
        
        Parameters
        ----------
        n1 : int
            The site number.
            
        Returns
        -------
        rho : ndarray
            Reduced density matrix in the number basis.
        """
        rho = sp.empty((self.q[n], self.q[n]), dtype=sp.complex128)

        r_n = self.r[n]
        r_nm1 = sp.empty_like(self.r[n - 1])
        for s in xrange(self.q[n]):
            for t in xrange(self.q[n]):
                r_nm1 = m.mmul(self.A[n][t], r_n, m.H(self.A[n][s]))
                rho[s, t] = m.adot(self.l[n - 1], r_nm1)
        return rho
Ejemplo n.º 4
0
 def check_RCF(self):
     """Tests for right canonical form.
     
     Uses the criteria listed in sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2.
     
     This is a consistency check mainly intended for debugging purposes.
     
     FIXME: The tolerances appear to be too tight!
     
     Returns
     -------
     (rnsOK, ls_trOK, ls_pos, ls_diag, normOK) : tuple of bool
         rnsOK: Right orthonormalization is fullfilled (self.r[n] = eye)
         ls_trOK: all self.l[n] have trace 1
         ls_pos: all self.l[n] are positive-definite
         ls_diag: all self.l[n] are diagonal
         normOK: the state it normalized
     """
     rnsOK = True
     ls_trOK = True
     ls_herm = True
     ls_pos = True
     ls_diag = True
     
     for n in xrange(1, self.N + 1):
         rnsOK = rnsOK and sp.allclose(self.r[n], sp.eye(self.r[n].shape[0]), atol=self.eps*2, rtol=0)
         ls_herm = ls_herm and sp.allclose(self.l[n] - m.H(self.l[n]), 0, atol=self.eps*2)
         ls_trOK = ls_trOK and sp.allclose(sp.trace(self.l[n]), 1, atol=self.eps*1000, rtol=0)
         ls_pos = ls_pos and all(la.eigvalsh(self.l[n]) > 0)
         ls_diag = ls_diag and sp.allclose(self.l[n], sp.diag(self.l[n].diagonal()))
     
     normOK = sp.allclose(self.l[self.N], 1., atol=self.eps*1000, rtol=0)
     
     return (rnsOK, ls_trOK, ls_pos, ls_diag, normOK)
Ejemplo n.º 5
0
 def gauge_align(self, other, tol=1E-12):
     """Gauge-align the state with another.
     
     Given two states that differ only by a gauge-transformation
     and a phase, this makes equalizes the parameter tensors by performing 
     the required transformation.
     
     Parameters
     ----------
     other : EvoMPS_MPS_Uniform
         MPS with which to calculate the per-site fidelity.
     tol : float
         Tolerance for detecting per-site fidelity != 1.
         
     Returns
     -------
     Nothing if the per-site fidelity is 1. Otherwise:
         
     g : ndarray
         The gauge-transformation matrix used.
     g_i : ndarray
         The inverse of g.
     phi : complex
         The phase factor.
     """
     d, phi, gR = self.fidelity_per_site(other, full_output=True)
     
     if abs(d - 1) > tol:
         return
         
     gR = gR.reshape(self.D, self.D)
         
     try:
         g = other.r.inv().dotleft(gR)
     except:
         g = gR.dot(m.invmh(other.r))
         
     gi = la.inv(g)
     
     for s in xrange(self.q):
         self.A[s] = phi.conj() * gi.dot(self.A[s]).dot(g)
         
     self.l = m.H(g).dot(self.l.dot(g))
     
     self.r = gi.dot(self.r.dot(m.H(gi)))
         
     return g, gi, phi
Ejemplo n.º 6
0
    def density_2s(self, n1, n2):
        """Returns a reduced density matrix for a pair of (seperated) sites.
        
        The site number basis is used: rho[s * q[n1] + u, t * q[n1] + v]
        with 0 <= s, t < q[n1] and 0 <= u, v < q[n2].
        
        The state must be up-to-date -- see self.update()!
        
        Parameters
        ----------
        n1 : int
            The site number of the first site.
        n2 : int
            The site number of the second site (must be > n1).
            
        Returns
        -------
        rho : ndarray
            Reduced density matrix in the number basis.
        """
        rho = sp.empty((self.q[n1] * self.q[n2], self.q[n1] * self.q[n2]),
                       dtype=sp.complex128)

        for s2 in xrange(self.q[n2]):
            for t2 in xrange(self.q[n2]):
                r_n2 = m.mmul(self.A[n2][t2], self.r[n2], m.H(self.A[n2][s2]))

                r_n = r_n2
                for n in reversed(xrange(n1 + 1, n2)):
                    r_n = tm.eps_r_noop(r_n, self.A[n], self.A[n])

                for s1 in xrange(self.q[n1]):
                    for t1 in xrange(self.q[n1]):
                        r_n1 = m.mmul(self.A[n1][t1], r_n, m.H(self.A[n1][s1]))
                        tmp = m.adot(self.l[n1 - 1], r_n1)
                        rho[s1 * self.q[n1] + s2, t1 * self.q[n1] + t2] = tmp
        return rho
Ejemplo n.º 7
0
 def density_1s(self):
     """Returns a reduced density matrix for a single site.
     
     The site number basis is used: rho[s, t] 
     with 0 <= s, t < q.
     
     The state must be up-to-date -- see self.update()!
         
     Returns
     -------
     rho : ndarray
         Reduced density matrix in the number basis.
     """
     rho = np.empty((self.q, self.q), dtype=self.typ)
     for s in xrange(self.q):
         for t in xrange(self.q):                
             rho[s, t] = m.adot(self.l, m.mmul(self.A[t], self.r, m.H(self.A[s])))
     return rho
Ejemplo n.º 8
0
    def _calc_B_r_diss(self, op, K, C, n, set_eta=True):
        if self.q[n] * self.D[n] - self.D[n - 1] > 0:
            l_sqrt, l_sqrt_inv, r_sqrt, r_sqrt_inv = tm.calc_l_r_roots(
                self.l[n - 1],
                self.r[n],
                sanity_checks=self.sanity_checks,
                sc_data=("site", n))
            Vsh = tm.calc_Vsh(self.A[n],
                              r_sqrt,
                              sanity_checks=self.sanity_checks)
            x = self.calc_x(n, Vsh, l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv)
            if set_eta:
                self.eta[n] = sp.sqrt(mm.adot(x, x))

            B = sp.empty_like(self.A[n])
            for s in xrange(self.q[n]):
                B[s] = mm.mmul(l_sqrt_inv, x, mm.H(Vsh[s]), r_sqrt_inv)
            return B
        else:
            return None
Ejemplo n.º 9
0
    def calc_K_common(self, Kp1, C, lm1, rp1, A, Ap1):
        Dm1 = A.shape[1]
        q = A.shape[0]
        qp1 = Ap1.shape[0]

        K = sp.zeros((Dm1, Dm1), dtype=A.dtype)

        Hr = sp.zeros_like(K)

        for s in xrange(q):
            Ash = A[s].conj().T
            for t in xrange(qp1):
                test = Ap1[t]
                Hr += C[t, s].dot(rp1.dot(mm.H(test).dot(Ash)))
            K += A[s].dot(Kp1.dot(Ash))

        op_expect = mm.adot(lm1, Hr)

        K += Hr
        return K, op_expect
Ejemplo n.º 10
0
def calc_K(Kp1, C, lm1, rp1, A, Ap1, sanity_checks=False):
    Dm1 = A.shape[1]
    q = A.shape[0]
    qp1 = Ap1.shape[0]
    
    K = sp.zeros((Dm1, Dm1), dtype=A.dtype)
    
    Hr = sp.zeros_like(K)

    for s in xrange(q):
        Ash = A[s].conj().T
        for t in xrange(qp1):
            Hr += C[s, t].dot(rp1.dot(mm.H(Ap1[t]).dot(Ash)))

        K += A[s].dot(Kp1.dot(Ash))
        
    op_expect = mm.adot(lm1, Hr)
        
    K += Hr
    
    return K, op_expect
Ejemplo n.º 11
0
 def _calc_B_l(self, n, set_eta=True):
     if self.q[n] * self.D[n - 1] - self.D[n] > 0:
         l_sqrt, l_sqrt_inv, r_sqrt, r_sqrt_inv = tm.calc_l_r_roots(self.l[n - 1], 
                                                                self.r[n], 
                                                                zero_tol=self.zero_tol,
                                                                sanity_checks=self.sanity_checks,
                                                                sc_data=('site', n))
         
         Vsh = tm.calc_Vsh_l(self.A[n], l_sqrt, sanity_checks=self.sanity_checks)
         
         x = self.calc_x_l(n, Vsh, l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv)
         
         if set_eta:
             self.eta[n] = sp.sqrt(m.adot(x, x))
 
         B = sp.empty_like(self.A[n])
         for s in xrange(self.q[n]):
             B[s] = m.mmul(l_sqrt_inv, m.H(Vsh[s]), x, r_sqrt_inv)
         return B
     else:
         return None
Ejemplo n.º 12
0
    def overlap(self, other, sanity_checks=False):
        if not self.N == other.N:
            print "States must have same number of non-uniform sites!"
            return

        if not sp.all(self.D == other.D):
            print "States must have same bond-dimensions!"
            return

        if not sp.all(self.q == other.q):
            print "States must have same Hilbert-space dimensions!"
            return

        dL, phiL, gLl = self.uni_l.fidelity_per_site(other.uni_l,
                                                     full_output=True,
                                                     left=True)

        dR, phiR, gRr = self.uni_r.fidelity_per_site(other.uni_r,
                                                     full_output=True,
                                                     left=False)

        gLl = gLl.reshape(self.uni_l.D, self.uni_l.D)
        gRr = gRr.reshape(self.uni_r.D, self.uni_r.D)

        gr = mm.H(la.inv(gRr).dot(sp.asarray(self.uni_r.r[-1])))
        gri = mm.H(la.inv(sp.asarray(self.uni_r.r[-1])).dot(gRr))

        #        if sanity_checks: #FIXME: Not gonna work for L > 1....
        #            AR = other.uni_r.A.copy()
        #            for s in xrange(AR.shape[0]):
        #                AR[s] = gr.dot(AR[s]).dot(gri)
        #
        #            print la.norm(AR - self.uni_r.A)

        r = gr.dot(sp.asarray(other.uni_r.r)).dot(mm.H(gr))
        fac = la.norm(sp.asarray(self.uni_r.r)) / la.norm(r)
        gr *= sp.sqrt(fac)
        gri /= sp.sqrt(fac)

        if sanity_checks:
            r *= fac
            print la.norm(r - self.uni_r.r[-1])

#            AN = other.A[self.N].copy()
#            for s in xrange(AN.shape[0]):
#                AN[s] = AN[s].dot(gri)
#            r = tm.eps_r_noop(self.uni_r.r, AN, AN)
#            print la.norm(r - other.r[self.N - 1])

        gl = la.inv(sp.asarray(self.uni_l.l[-1])).dot(gLl)
        gli = la.inv(gLl).dot(sp.asarray(self.uni_l.l[-1]))

        l = mm.H(gli).dot(sp.asarray(other.uni_l.l[-1])).dot(gli)
        fac = la.norm(sp.asarray(self.uni_l.l[-1])) / la.norm(l)

        gli *= sp.sqrt(fac)
        gl /= sp.sqrt(fac)

        if sanity_checks:
            l *= fac
            print la.norm(l - self.uni_l.l[-1])

            l = mm.H(gli).dot(sp.asarray(other.uni_l.l[-1])).dot(gli)
            print la.norm(l - self.uni_l.l[-1])

        #print (dL, dR, phiL, phiR)

        if not abs(dL - 1) < 1E-12:
            print "Left bulk states do not match!"
            return 0

        if not abs(dR - 1) < 1E-12:
            print "Right bulk states do not match!"
            return 0

        AN = other.A[self.N].copy()
        for s in xrange(AN.shape[0]):
            AN[s] = AN[s].dot(gri)

        A1 = other.A[1].copy()
        for s in xrange(A1.shape[0]):
            A1[s] = gl.dot(A1[s])

        r = tm.eps_r_noop(self.uni_r.r[-1], self.A[self.N], AN)
        for n in xrange(self.N - 1, 1, -1):
            r = tm.eps_r_noop(r, self.A[n], other.A[n])
        r = tm.eps_r_noop(r, self.A[1], A1)

        return mm.adot(self.uni_l.l[-1], r)
Ejemplo n.º 13
0
    def calc_lr(self):
        """Determines the dominant left and right eigenvectors of the transfer 
        operator E.
        
        Uses an iterative method (e.g. Arnoldi iteration) to determine the
        largest eigenvalue and the correspoinding left and right eigenvectors,
        which are stored as self.l and self.r respectively.
        
        The parameter tensor self.A is rescaled so that the largest eigenvalue
        is equal to 1 (thus normalizing the state).
        
        The largest eigenvalue is assumed to be non-degenerate.
        
        """
        tmp = np.empty_like(self.tmp)
        
        #Make sure...
        self.l_before_CF = np.asarray(self.l_before_CF)
        self.r_before_CF = np.asarray(self.r_before_CF)
        
        if self.ev_use_arpack:
            self.l, self.conv_l, self.itr_l = self._calc_lr_ARPACK(self.l_before_CF, tmp,
                                                   calc_l=True,
                                                   tol=self.itr_rtol,
                                                   k=self.ev_arpack_nev,
                                                   ncv=self.ev_arpack_ncv)
        else:
            self.l, self.conv_l, self.itr_l = self._calc_lr(self.l_before_CF, 
                                                    tmp, 
                                                    calc_l=True,
                                                    max_itr=self.pow_itr_max,
                                                    rtol=self.itr_rtol, 
                                                    atol=self.itr_atol)
                                        
        self.l_before_CF = self.l.copy()

        if self.ev_use_arpack:
            self.r, self.conv_r, self.itr_r = self._calc_lr_ARPACK(self.r_before_CF, tmp, 
                                                   calc_l=False,
                                                   tol=self.itr_rtol,
                                                   k=self.ev_arpack_nev,
                                                   ncv=self.ev_arpack_ncv)
        else:
            self.r, self.conv_r, self.itr_r = self._calc_lr(self.r_before_CF, 
                                                    tmp, 
                                                    calc_l=False,
                                                    max_itr=self.pow_itr_max,
                                                    rtol=self.itr_rtol, 
                                                    atol=self.itr_atol)
        self.r_before_CF = self.r.copy()
            
        #normalize eigenvectors:

        if self.symm_gauge:
            norm = m.adot(self.l, self.r).real
            itr = 0 
            while not np.allclose(norm, 1, atol=1E-13, rtol=0) and itr < 10:
                self.l *= 1. / ma.sqrt(norm)
                self.r *= 1. / ma.sqrt(norm)
                
                norm = m.adot(self.l, self.r).real
                
                itr += 1
                
            if itr == 10:
                log.warning("Warning: Max. iterations reached during normalization!")
        else:
            fac = self.D / np.trace(self.r).real
            self.l *= 1 / fac
            self.r *= fac

            norm = m.adot(self.l, self.r).real
            itr = 0 
            while not np.allclose(norm, 1, atol=1E-13, rtol=0) and itr < 10:
                self.l *= 1. / norm
                norm = m.adot(self.l, self.r).real
                itr += 1
                
            if itr == 10:
                log.warning("Warning: Max. iterations reached during normalization!")

        if self.sanity_checks:
            if not np.allclose(tm.eps_l_noop(self.l, self.A, self.A), self.l,
            rtol=self.itr_rtol*self.check_fac, 
            atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Left eigenvector bad! Off by: %s",
                            la.norm(tm.eps_l_noop(self.l, self.A, self.A) - self.l))
                       
            if not np.allclose(tm.eps_r_noop(self.r, self.A, self.A), self.r,
            rtol=self.itr_rtol*self.check_fac,
            atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Right eigenvector bad! Off by: %s",
                            la.norm(tm.eps_r_noop(self.r, self.A, self.A) - self.r))
            
            if not np.allclose(self.l, m.H(self.l),
            rtol=self.itr_rtol*self.check_fac, 
            atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: l is not hermitian!")

            if not np.allclose(self.r, m.H(self.r),
            rtol=self.itr_rtol*self.check_fac, 
            atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: r is not hermitian!")
            
            if not np.all(la.eigvalsh(self.l) > 0):
                log.warning("Sanity check failed: l is not pos. def.!")
                
            if not np.all(la.eigvalsh(self.r) > 0):
                log.warning("Sanity check failed: r is not pos. def.!")
            
            norm = m.adot(self.l, self.r)
            if not np.allclose(norm, 1.0, atol=1E-13, rtol=0):
                log.warning("Sanity check failed: Bad norm = %s", norm)
Ejemplo n.º 14
0
    def calc_B(self, n, set_eta=True):
        """Generates the B[n] tangent vector corresponding to physical evolution of the state.

        In other words, this returns B[n][x*] (equiv. eqn. (47) of
        arXiv:1103.0936v2 [cond-mat.str-el])
        with x* the parameter matrices satisfying the Euler-Lagrange equations
        as closely as possible.
        
        In the case of Bc, use the general Bc generated in calc_B_centre().
        """
        if n == self.N_centre:
            B, eta_c = self.calc_B_centre()
            if set_eta:
                self.eta[self.N_centre] = eta_c
        else:
            l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv = self.calc_l_r_roots(n)

            if n > self.N_centre:
                Vsh = tm.calc_Vsh(self.A[n],
                                  r_sqrt,
                                  sanity_checks=self.sanity_checks)
                x = self.calc_x(n,
                                Vsh,
                                l_sqrt,
                                r_sqrt,
                                l_sqrt_inv,
                                r_sqrt_inv,
                                right=True)

                B = sp.empty_like(self.A[n])
                for s in xrange(self.q[n]):
                    B[s] = mm.mmul(l_sqrt_inv, x, mm.H(Vsh[s]), r_sqrt_inv)

                if self.sanity_checks:
                    M = tm.eps_r_noop(self.r[n], B, self.A[n])
                    if not sp.allclose(M, 0):
                        print "Sanity Fail in calc_B!: B_%u does not satisfy GFC!" % n
            else:
                Vsh = tm.calc_Vsh_l(self.A[n],
                                    l_sqrt,
                                    sanity_checks=self.sanity_checks)
                x = self.calc_x(n,
                                Vsh,
                                l_sqrt,
                                r_sqrt,
                                l_sqrt_inv,
                                r_sqrt_inv,
                                right=False)

                B = sp.empty_like(self.A[n])
                for s in xrange(self.q[n]):
                    B[s] = mm.mmul(l_sqrt_inv, mm.H(Vsh[s]), x, r_sqrt_inv)

                if self.sanity_checks:
                    M = tm.eps_l_noop(self.l[n - 1], B, self.A[n])
                    if not sp.allclose(M, 0):
                        print "Sanity Fail in calc_B!: B_%u does not satisfy GFC!" % n

            if set_eta:
                self.eta[n] = sp.sqrt(mm.adot(x, x))

        return B
Ejemplo n.º 15
0
    def calc_B_centre(self):
        """Calculate the optimal B_centre given right gauge-fixing on n_centre+1..N and
        left gauge-fixing on 1..n_centre-1.
        
        We use the non-norm-preserving K's, since the norm-preservation
        is not needed elsewhere. It is cleaner to subtract the relevant
        norm-changing terms from the K's here than to generate all K's
        with norm-preservation.
        """
        Bc = sp.empty_like(self.A[self.N_centre])

        Nc = self.N_centre

        try:
            rc_i = self.r[Nc].inv()
        except AttributeError:
            rc_i = mm.invmh(self.r[Nc])

        try:
            lcm1_i = self.l[Nc - 1].inv()
        except AttributeError:
            lcm1_i = mm.invmh(self.l[Nc - 1])

        Acm1 = self.A[Nc - 1]
        Ac = self.A[Nc]
        Acp1 = self.A[Nc + 1]
        rc = self.r[Nc]
        rcp1 = self.r[Nc + 1]
        lcm1 = self.l[Nc - 1]
        lcm2 = self.l[Nc - 2]

        #Note: this is a 'bra-vector'
        K_l_cm1 = self.K_l[Nc - 1] - lcm1 * mm.adot_noconj(
            self.K_l[Nc - 1], self.r[Nc - 1])

        Kcp1 = self.K[Nc + 1] - rc * mm.adot(self.l[Nc], self.K[Nc + 1])

        Cc = self.C[Nc] - self.h_expect[Nc] * self.AAc
        Ccm1 = self.C[Nc - 1] - self.h_expect[Nc - 1] * self.AAcm1

        for s in xrange(self.q[1]):
            try:  #3
                Bc[s] = Ac[s].dot(rc_i.dot_left(Kcp1))
            except AttributeError:
                Bc[s] = Ac[s].dot(Kcp1.dot(rc_i))

            for t in xrange(self.q[2]):  #1
                try:
                    Bc[s] += Cc[s,
                                t].dot(rcp1.dot(rc_i.dot_left(mm.H(Acp1[t]))))
                except AttributeError:
                    Bc[s] += Cc[s, t].dot(rcp1.dot(mm.H(Acp1[t]).dot(rc_i)))

            Bcsbit = K_l_cm1.dot(Ac[s])  #4

            for t in xrange(self.q[0]):  #2
                Bcsbit += mm.H(Acm1[t]).dot(lcm2.dot(Ccm1[t, s]))

            Bc[s] += lcm1_i.dot(Bcsbit)

        rb = tm.eps_r_noop(rc, Bc, Bc)
        eta = sp.sqrt(mm.adot(lcm1, rb))

        return Bc, eta
Ejemplo n.º 16
0
    def restore_RCF(self, ret_g=False, zero_tol=None):
        """Restores right canonical form.
        
        In this form, self.r = sp.eye(self.D) and self.l is diagonal, with
        the squared Schmidt coefficients corresponding to the half-chain
        decomposition as eigenvalues.
        
        Parameters
        ----------
        ret_g : bool
            Whether to return the gauge-transformation matrices used.
            
        Returns
        -------
        g, g_i : ndarray
            Gauge transformation matrix g and its inverse g_i.
        """
        if zero_tol is None:
            zero_tol = self.zero_tol
        
        #First get G such that r = eye
        G, G_i, rank = tm.herm_fac_with_inv(self.r, lower=True, zero_tol=zero_tol,
                                            return_rank=True)

        self.l = m.mmul(m.H(G), self.l, G)
        
        #Now bring l into diagonal form, trace = 1 (guaranteed by r = eye..?)
        ev, EV = la.eigh(self.l)

        G = G.dot(EV)
        G_i = m.H(EV).dot(G_i)
        
        for s in xrange(self.q):
            self.A[s] = m.mmul(G_i, self.A[s], G)
            
        #ev contains the squares of the Schmidt coefficients,
        self.S_hc = - np.sum(ev * sp.log2(ev))
        
        self.l = m.simple_diag_matrix(ev, dtype=self.typ)
        
        r_old = self.r
        
        if rank == self.D:
            self.r = m.eyemat(self.D, self.typ)
        else:
            self.r = sp.zeros((self.D), dtype=self.typ)
            self.r[-rank:] = 1
            self.r = m.simple_diag_matrix(self.r, dtype=self.typ)

        if self.sanity_checks:            
            r_ = m.mmul(G_i, r_old, m.H(G_i)) 
            
            if not np.allclose(self.r, r_, 
                               rtol=self.itr_rtol*self.check_fac,
                               atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: RestoreRCF, bad r (bad GT).")
            
            l = tm.eps_l_noop(self.l, self.A, self.A)
            r = tm.eps_r_noop(self.r, self.A, self.A)
            
            if not np.allclose(r, self.r,
                               rtol=self.itr_rtol*self.check_fac, 
                               atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Restore_RCF, r not eigenvector! %s", la.norm(r - self.r))

            if not np.allclose(l, self.l,
                               rtol=self.itr_rtol*self.check_fac, 
                               atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Restore_RCF, l not eigenvector! %s", la.norm(l - self.l))
        
        if ret_g:
            return G, G_i
        else:
            return
Ejemplo n.º 17
0
    def restore_SCF(self, ret_g=False, zero_tol=None):
        """Restores symmetric canonical form.
        
        In this canonical form, self.l == self.r and are diagonal matrices
        with the Schmidt coefficients corresponding to the half-chain
        decomposition form the diagonal entries.
        
        Parameters
        ----------
        ret_g : bool
            Whether to return the gauge-transformation matrices used.
            
        Returns
        -------
        g, g_i : ndarray
            Gauge transformation matrix g and its inverse g_i.
        """
        if zero_tol is None:
            zero_tol = self.zero_tol
        
        X, Xi = tm.herm_fac_with_inv(self.r, lower=True, zero_tol=zero_tol)
        
        Y, Yi = tm.herm_fac_with_inv(self.l, lower=False, zero_tol=zero_tol)          
            
        U, sv, Vh = la.svd(Y.dot(X))
        
        #s contains the Schmidt coefficients,
        lam = sv**2
        self.S_hc = - np.sum(lam * sp.log2(lam))
        
        S = m.simple_diag_matrix(sv, dtype=self.typ)
        Srt = S.sqrt()
        
        g = m.mmul(Srt, Vh, Xi)
        
        g_i = m.mmul(Yi, U, Srt)
        
        for s in xrange(self.q):
            self.A[s] = m.mmul(g, self.A[s], g_i)
                
        if self.sanity_checks:
            Sfull = np.asarray(S)
            
            if not np.allclose(g.dot(g_i), np.eye(self.D)):
                log.warning("Sanity check failed! Restore_SCF, bad GT!")
            
            l = m.mmul(m.H(g_i), self.l, g_i)
            r = m.mmul(g, self.r, m.H(g))
            
            if not np.allclose(Sfull, l):
                log.warning("Sanity check failed: Restorce_SCF, left failed!")
                
            if not np.allclose(Sfull, r):
                log.warning("Sanity check failed: Restorce_SCF, right failed!")
                
            l = tm.eps_l_noop(Sfull, self.A, self.A)
            r = tm.eps_r_noop(Sfull, self.A, self.A)
            
            if not np.allclose(Sfull, l, rtol=self.itr_rtol*self.check_fac, 
                               atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Restorce_SCF, left bad!")
                
            if not np.allclose(Sfull, r, rtol=self.itr_rtol*self.check_fac, 
                               atol=self.itr_atol*self.check_fac):
                log.warning("Sanity check failed: Restorce_SCF, right bad!")

        self.l = S
        self.r = S
        
        if ret_g:
            return g, g_i
        else:
            return