Beispiel #1
0
 def calc_B1(self):
     """Calculate the optimal B1 given right gauge-fixing on B2..N and
     no gauge-fixing on B1.
     
     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.
     """
     B1 = sp.empty_like(self.A[1])
     
     try:
         r1_i = self.r[1].inv()
     except AttributeError:
         r1_i = mm.invmh(self.r[1])
         
     try:
         l0_i = self.l[0].inv()
     except AttributeError:
         l0_i = mm.invmh(self.l[0])
     
     A0 = self.A[0]
     A1 = self.A[1]
     A2 = self.A[2]
     r1 = self.r[1]
     r2 = self.r[2]
     l0 = self.l[0]
     
     KLh = mm.H(self.u_gnd_l.K_left - l0 * mm.adot(self.u_gnd_l.K_left, self.r[0]))
     K2 = self.K[2] - r1 * mm.adot(self.l[1], self.K[2])
     
     C1 = self.C[1] - self.h_expect[1] * self.AA1
     C0 = self.C[0] - self.h_expect[0] * self.AA0
     
     for s in xrange(self.q[1]):
         try:
             B1[s] = A1[s].dot(r1_i.dot_left(K2))
         except AttributeError:
             B1[s] = A1[s].dot(K2.dot(r1_i))
         
         for t in xrange(self.q[2]):
             try:
                 B1[s] += C1[s, t].dot(r2.dot(r1_i.dot_left(mm.H(A2[t]))))
             except AttributeError:
                 B1[s] += C1[s, t].dot(r2.dot(mm.H(A2[t]).dot(r1_i)))                    
             
         B1sbit = KLh.dot(A1[s])
                         
         for t in xrange(self.q[0]):
             B1sbit += mm.H(A0[t]).dot(l0.dot(C0[t,s]))
             
         B1[s] += l0_i.dot(B1sbit)
        
     rb = sp.zeros_like(self.r[0])
     for s in xrange(self.q[1]):
         rb += B1[s].dot(r1.dot(mm.H(B1[s])))
     eta = sp.sqrt(mm.adot(l0, rb))
             
     return B1, eta
Beispiel #2
0
    def calc_l_r_roots(self, n):
        """Returns the matrix square roots (and inverses) needed to calculate B.
        
        Hermiticity of l[n] and r[n] is used to speed this up.
        If an exception occurs here, it is probably because these matrices
        are not longer Hermitian (enough).
        """
        l_sqrt, evd = m.sqrtmh(self.l[n - 1], ret_evd=True)
        l_sqrt_inv = m.invmh(l_sqrt, evd=evd)

        r_sqrt, evd =  m.sqrtmh(self.r[n], ret_evd=True)
        r_sqrt_inv = m.invmh(r_sqrt, evd=evd)
        
        return l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv
Beispiel #3
0
 def __init__(self, tdvp, n, KLnm1, tau=1, sanity_checks=False):
     """
     """
     self.D = tdvp.D
     self.q = tdvp.q
     self.tdvp = tdvp
     self.n = n
     self.KLnm1 = KLnm1
     
     self.sanity_checks = sanity_checks
     self.sanity_tol = 1E-12
     
     d = self.D[n - 1] * self.D[n] * self.q[n]
     self.shape = (d, d)
     
     self.dtype = sp.dtype(tdvp.typ)
     
     self.calls = 0
     
     self.tau = tau
     
     if n > 1:
         try:
             self.lm1_i = tdvp.l[n - 1].inv()
         except AttributeError:
             self.lm1_i = m.invmh(tdvp.l[n - 1])
     else:
         self.lm1_i = tdvp.l[n - 1]
Beispiel #4
0
    def calc_l_r_roots(self, n):
        """Returns the matrix square roots (and inverses) needed to calculate B.

        Hermiticity of l[n] and r[n] is used to speed this up.
        If an exception occurs here, it is probably because these matrices
        are no longer Hermitian (enough).
        
        If l[n] or r[n] are diagonal or the identity, further optimizations are
        used.
        """
        try:
            l_sqrt = self.l[n - 1].sqrt()
        except AttributeError:
            l_sqrt, evd = mm.sqrtmh(self.l[n - 1], ret_evd=True)

        try:
            l_sqrt_inv = l_sqrt.inv()
        except AttributeError:
            l_sqrt_inv = mm.invmh(l_sqrt, evd=evd)

        try:
            r_sqrt = self.r[n].sqrt()
        except AttributeError:
            r_sqrt, evd =  mm.sqrtmh(self.r[n], ret_evd=True)

        try:
            r_sqrt_inv = r_sqrt.inv()
        except AttributeError:
            r_sqrt_inv = mm.invmh(r_sqrt, evd=evd)

        if self.sanity_checks:
            if not sp.allclose(mm.mmul(l_sqrt, l_sqrt), self.l[n - 1]):
                print "Sanity Fail in calc_l_r_roots: Bad l_sqrt_%u" % (n - 1)
            if not sp.allclose(mm.mmul(r_sqrt, r_sqrt), self.r[n]):
                print "Sanity Fail in calc_l_r_roots: Bad r_sqrt_%u" % (n)
            if not sp.allclose(mm.mmul(l_sqrt, l_sqrt_inv), sp.eye(l_sqrt.shape[0])):
                print "Sanity Fail in calc_l_r_roots: Bad l_sqrt_inv_%u" % (n - 1)
            if not sp.allclose(mm.mmul(r_sqrt, r_sqrt_inv), sp.eye(r_sqrt.shape[0])):
                print "Sanity Fail in calc_l_r_roots: Bad r_sqrt_inv_%u" % (n)

        return l_sqrt, r_sqrt, l_sqrt_inv, r_sqrt_inv
Beispiel #5
0
 def calc_l_r_roots(self):
     try:
         self.l_sqrt = self.l.sqrt()
         self.l_sqrt_i = self.l_sqrt.inv()
     except AttributeError:
         self.l_sqrt, evd = m.sqrtmh(self.l, ret_evd=True)
         self.l_sqrt_i = m.invmh(self.l_sqrt, evd=evd)
         
     try:
         self.r_sqrt = self.r.sqrt()
         self.r_sqrt_i = self.r_sqrt.inv()
     except AttributeError:
         self.r_sqrt, evd = m.sqrtmh(self.r, ret_evd=True)
         self.r_sqrt_i = m.invmh(self.r_sqrt, evd=evd)
     
     if self.sanity_checks:
         if not np.allclose(self.l_sqrt.dot(self.l_sqrt), self.l):
             print "Sanity check failed: l_sqrt is bad!"
         if not np.allclose(self.l_sqrt.dot(self.l_sqrt_i), np.eye(self.D)):
             print "Sanity check failed: l_sqrt_i is bad!"
         if not np.allclose(self.r_sqrt.dot(self.r_sqrt), self.r):
             print "Sanity check failed: r_sqrt is bad!"
         if (not np.allclose(self.r_sqrt.dot(self.r_sqrt_i), np.eye(self.D))):
             print "Sanity check failed: r_sqrt_i is bad!"
Beispiel #6
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
    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
Beispiel #8
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