Ejemplo n.º 1
0
    def _restore_CF_diag(self, dbg=False):
        nc = self.N_centre

        #Want: r[0 <= n < nc] diagonal
        Ui = sp.eye(self.D[nc], dtype=self.typ)
        for n in xrange(nc, 0, -1):
            self.r[n - 1], Um1, Um1_i = tm.restore_LCF_r(self.A[n], self.r[n],
                                                         Ui, sanity_checks=self.sanity_checks)
            Ui = Um1_i

        #Now U is U_0
        U = Um1
        for s in xrange(self.q[0]):
            self.uni_l.A[0][s] = U.dot(self.uni_l.A[0][s])
            self.uni_l.A[-1][s] = self.uni_l.A[-1][s].dot(Ui)
        self.uni_l.r[-1] = U.dot(self.uni_l.r[-1].dot(U.conj().T))

        #And now: l[nc <= n <= N] diagonal
        if dbg:
            Um1 = sp.eye(self.D[nc - 1], dtype=self.typ)
        else:
            Um1 = mm.eyemat(self.D[nc - 1], dtype=self.typ) #FIXME: This only works if l[nc - 1] is a special matrix type        
        for n in xrange(nc, self.N + 1):
            self.l[n], U, Ui = tm.restore_RCF_l(self.A[n], self.l[n - 1], Um1,
                                                sanity_checks=self.sanity_checks)
            Um1 = U

        #Now, Um1 = U_N
        Um1_i = Ui
        for s in xrange(self.q[0]):
            self.uni_r.A[0][s] = Um1.dot(self.uni_r.A[0][s])
            self.uni_r.A[-1][s] = self.uni_r.A[-1][s].dot(Um1_i)
        self.uni_r.l[-1] = Um1_i.conj().T.dot(self.uni_r.l[-1].dot(Um1_i))
Ejemplo n.º 2
0
    def _restore_CF_diag(self, dbg=False):
        nc = self.N_centre

        #Want: r[0 <= n < nc] diagonal
        Ui = sp.eye(self.D[nc], dtype=self.typ)
        for n in xrange(nc, 0, -1):
            self.r[n - 1], Um1, Um1_i = tm.restore_LCF_r(
                self.A[n], self.r[n], Ui, sanity_checks=self.sanity_checks)
            Ui = Um1_i

        #Now U is U_0
        U = Um1
        for s in xrange(self.q[0]):
            self.uni_l.A[0][s] = U.dot(self.uni_l.A[0][s])
            self.uni_l.A[-1][s] = self.uni_l.A[-1][s].dot(Ui)
        self.uni_l.r[-1] = U.dot(self.uni_l.r[-1].dot(U.conj().T))

        #And now: l[nc <= n <= N] diagonal
        if dbg:
            Um1 = sp.eye(self.D[nc - 1], dtype=self.typ)
        else:
            Um1 = mm.eyemat(
                self.D[nc - 1], dtype=self.typ
            )  #FIXME: This only works if l[nc - 1] is a special matrix type
        for n in xrange(nc, self.N + 1):
            self.l[n], U, Ui = tm.restore_RCF_l(
                self.A[n],
                self.l[n - 1],
                Um1,
                sanity_checks=self.sanity_checks)
            Um1 = U

        #Now, Um1 = U_N
        Um1_i = Ui
        for s in xrange(self.q[0]):
            self.uni_r.A[0][s] = Um1.dot(self.uni_r.A[0][s])
            self.uni_r.A[-1][s] = self.uni_r.A[-1][s].dot(Um1_i)
        self.uni_r.l[-1] = Um1_i.conj().T.dot(self.uni_r.l[-1].dot(Um1_i))
Ejemplo n.º 3
0
    def _restore_CF_diag(self):
        nc = self.N_centre

        self.S_hc = sp.zeros((self.N + 1), dtype=sp.complex128)

        #Want: r[0 <= n < nc] diagonal
        Ui = sp.eye(self.D[nc], dtype=self.typ)
        for n in xrange(nc, 0, -1):
            self.r[n - 1], Um1, Um1_i = tm.restore_LCF_r(self.A[n], self.r[n],
                                                         Ui, sanity_checks=self.sanity_checks)

            self.S_hc[n - 1] = -sp.sum(self.r[n - 1].diag * sp.log2(self.r[n - 1].diag))

            Ui = Um1_i

        #Now U is U_0
        U = Um1
        for s in xrange(self.q[0]):
            self.A[0][s] = U.dot(self.A[0][s]).dot(Ui)
        self.uni_l.r = U.dot(self.uni_l.r.dot(U.conj().T))

        #And now: l[nc <= n <= N] diagonal
        Um1 = mm.eyemat(self.D[nc - 1], dtype=self.typ)
        for n in xrange(nc, self.N + 1):
            self.l[n], U, Ui = tm.restore_RCF_l(self.A[n], self.l[n - 1], Um1,
                                                sanity_checks=self.sanity_checks)

            self.S_hc[n] = -sp.sum(self.l[n].diag * sp.log2(self.l[n].diag))

            Um1 = U

        #Now, Um1 = U_N
        Um1_i = Ui
        for s in xrange(self.q[0]):
            self.A[self.N + 1][s] = Um1.dot(self.A[self.N + 1][s]).dot(Um1_i)
        self.uni_r.l = Um1_i.conj().T.dot(self.uni_r.l.dot(Um1_i))
Ejemplo n.º 4
0
    def restore_RCF(self, update_l=True, normalize=True, diag_l=True):
        """Use a gauge-transformation to restore right canonical form.
        
        Implements the conditions for right canonical form from sub-section
        3.1, theorem 1 of arXiv:quant-ph/0608197v2.
        
        This performs two 'almost' gauge transformations, where the 'almost'
        means we allow the norm to vary (if "normalize" = True).
        
        The last step (A[1]) is done diffently to the others since G[0],
        the gauge-transf. matrix, is just a number, which can be found more
        efficiently and accurately without using matrix methods.
        
        The last step (A[1]) is important because, if we have successfully made 
        r[1] = 1 in the previous steps, it fully determines the normalization 
        of the state via r[0] ( = l[N]).
        
        Optionally (normalize=False), the function will not attempt to make
        A[1] satisfy the orthonorm. condition, and will take G[0] = 1 = G[N],
        thus performing a pure gauge-transformation, but not ensuring complete
        canonical form.
        
        It is also possible to begin the process from a site n other than N,
        in case the sites > n are known to be in the desired form already.
        
        It is also possible to skip the diagonalization of the l's, such that
        only the right orthonormalization condition (r_n = eye) is met.
        
        By default, the l's are updated even if diag_l=False.
        
        Parameters
        ----------
        update_l : bool
            Whether to call calc_l() after completion (defaults to True)
        normalize : bool
            Whether to also attempt to normalize the state.
        diag_l : bool
            Whether to put l in diagonal form (defaults to True)
        """   
        start = self.N
        
        G_n_i = sp.eye(self.D[start], dtype=self.typ) #This is actually just the number 1
        for n in xrange(start, 1, -1):
            self.r[n - 1], G_n, G_n_i = tm.restore_RCF_r(self.A[n], self.r[n], 
                                                         G_n_i, sc_data=('site', n),
                                                         zero_tol=self.zero_tol,
                                                         sanity_checks=self.sanity_checks)
        
        #Now do A[1]...
        #Apply the remaining G[1]^-1 from the previous step.
        for s in xrange(self.q[1]):                
            self.A[1][s] = m.mmul(self.A[1][s], G_n_i)
                    
        #Now finish off
        tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0])
        
        if normalize:
            G0 = 1. / sp.sqrt(self.r[0].squeeze().real)
            self.A[1] *= G0
            self.r[0][:] = 1
            
            if self.sanity_checks:
                r0 = tm.eps_r_noop(self.r[1], self.A[1], self.A[1])
                if not sp.allclose(r0, 1, atol=1E-12, rtol=1E-12):
                    log.warning("Sanity Fail in restore_RCF!: r_0 is bad / norm failure")

        if diag_l:
            G_nm1 = sp.eye(self.D[0], dtype=self.typ)
            for n in xrange(1, self.N):
                self.l[n], G_nm1, G_nm1_i = tm.restore_RCF_l(self.A[n],
                                                             self.l[n - 1],
                                                             G_nm1,
                                                             self.sanity_checks)

            #Apply remaining G_Nm1 to A[N]
            n = self.N
            for s in xrange(self.q[n]):
                self.A[n][s] = m.mmul(G_nm1, self.A[n][s])

            #Deal with final, scalar l[N]
            tm.eps_l_noop_inplace(self.l[n - 1], self.A[n], self.A[n], out=self.l[n])

            if self.sanity_checks:
                if not sp.allclose(self.l[self.N].real, 1, atol=1E-12, rtol=1E-12):
                    log.warning("Sanity Fail in restore_RCF!: l_N is bad / norm failure")
                    log.warning("l_N = %s", self.l[self.N].squeeze().real)
                
                for n in xrange(1, self.N + 1):
                    r_nm1 = tm.eps_r_noop(self.r[n], self.A[n], self.A[n])
                    #r_nm1 = tm.eps_r_noop(m.eyemat(self.D[n], self.typ), self.A[n], self.A[n])
                    if not sp.allclose(r_nm1, self.r[n - 1], atol=1E-11, rtol=1E-11):
                        log.warning("Sanity Fail in restore_RCF!: r_%u is bad (off by %g)", n, la.norm(r_nm1 - self.r[n - 1]))
        elif update_l:
            self.calc_l()
Ejemplo n.º 5
0
    def restore_RCF(self, update_l=True, normalize=True, diag_l=True):
        """Use a gauge-transformation to restore right canonical form.
        
        Implements the conditions for right canonical form from sub-section
        3.1, theorem 1 of arXiv:quant-ph/0608197v2.
        
        This performs two 'almost' gauge transformations, where the 'almost'
        means we allow the norm to vary (if "normalize" = True).
        
        The last step (A[1]) is done diffently to the others since G[0],
        the gauge-transf. matrix, is just a number, which can be found more
        efficiently and accurately without using matrix methods.
        
        The last step (A[1]) is important because, if we have successfully made 
        r[1] = 1 in the previous steps, it fully determines the normalization 
        of the state via r[0] ( = l[N]).
        
        Optionally (normalize=False), the function will not attempt to make
        A[1] satisfy the orthonorm. condition, and will take G[0] = 1 = G[N],
        thus performing a pure gauge-transformation, but not ensuring complete
        canonical form.
        
        It is also possible to begin the process from a site n other than N,
        in case the sites > n are known to be in the desired form already.
        
        It is also possible to skip the diagonalization of the l's, such that
        only the right orthonormalization condition (r_n = eye) is met.
        
        By default, the l's are updated even if diag_l=False.
        
        Parameters
        ----------
        update_l : bool
            Whether to call calc_l() after completion (defaults to True)
        normalize : bool
            Whether to also attempt to normalize the state.
        diag_l : bool
            Whether to put l in diagonal form (defaults to True)
        """
        start = self.N

        G_n_i = sp.eye(self.D[start],
                       dtype=self.typ)  #This is actually just the number 1
        for n in xrange(start, 1, -1):
            self.r[n - 1], G_n, G_n_i = tm.restore_RCF_r(
                self.A[n],
                self.r[n],
                G_n_i,
                sc_data=('site', n),
                zero_tol=self.zero_tol,
                sanity_checks=self.sanity_checks)

        #Now do A[1]...
        #Apply the remaining G[1]^-1 from the previous step.
        for s in xrange(self.q[1]):
            self.A[1][s] = m.mmul(self.A[1][s], G_n_i)

        #Now finish off
        tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0])

        if normalize:
            G0 = 1. / sp.sqrt(self.r[0].squeeze().real)
            self.A[1] *= G0
            self.r[0][:] = 1

            if self.sanity_checks:
                r0 = tm.eps_r_noop(self.r[1], self.A[1], self.A[1])
                if not sp.allclose(r0, 1, atol=1E-12, rtol=1E-12):
                    log.warning(
                        "Sanity Fail in restore_RCF!: r_0 is bad / norm failure"
                    )

        if diag_l:
            G_nm1 = sp.eye(self.D[0], dtype=self.typ)
            for n in xrange(1, self.N):
                self.l[n], G_nm1, G_nm1_i = tm.restore_RCF_l(
                    self.A[n], self.l[n - 1], G_nm1, self.sanity_checks)

            #Apply remaining G_Nm1 to A[N]
            n = self.N
            for s in xrange(self.q[n]):
                self.A[n][s] = m.mmul(G_nm1, self.A[n][s])

            #Deal with final, scalar l[N]
            tm.eps_l_noop_inplace(self.l[n - 1],
                                  self.A[n],
                                  self.A[n],
                                  out=self.l[n])

            if self.sanity_checks:
                if not sp.allclose(
                        self.l[self.N].real, 1, atol=1E-12, rtol=1E-12):
                    log.warning(
                        "Sanity Fail in restore_RCF!: l_N is bad / norm failure"
                    )
                    log.warning("l_N = %s", self.l[self.N].squeeze().real)

                for n in xrange(1, self.N + 1):
                    r_nm1 = tm.eps_r_noop(self.r[n], self.A[n], self.A[n])
                    #r_nm1 = tm.eps_r_noop(m.eyemat(self.D[n], self.typ), self.A[n], self.A[n])
                    if not sp.allclose(
                            r_nm1, self.r[n - 1], atol=1E-11, rtol=1E-11):
                        log.warning(
                            "Sanity Fail in restore_RCF!: r_%u is bad (off by %g)",
                            n, la.norm(r_nm1 - self.r[n - 1]))
        elif update_l:
            self.calc_l()