Пример #1
0
    def _calc_lr(self, x, tmp, calc_l=False, A1=None, A2=None, rescale=True,
                 max_itr=1000, rtol=1E-14, atol=1E-14):
        """Power iteration to obtain eigenvector corresponding to largest
           eigenvalue.
           
           x is modified in place.
        """        
        if A1 is None:
            A1 = self.A
        if A2 is None:
            A2 = self.A
                        
        try:
            norm = la.get_blas_funcs("nrm2", [x])
        except (ValueError, AttributeError):
            norm = np.linalg.norm
            
#        try:
#            allclose = ac.allclose_mat
#        except:
#            allclose = np.allclose
#            print "Falling back to numpy allclose()!"
        
        n = x.size #we will scale x so that stuff doesn't get too small

        x *= n / norm(x.ravel())
        tmp[:] = x
        for i in xrange(max_itr):
            x[:] = tmp
            if calc_l:
                tm.eps_l_noop_inplace(x, A1, A2, tmp)
            else:
                tm.eps_r_noop_inplace(x, A1, A2, tmp)
            ev_mag = norm(tmp.ravel()) / n
            ev = (tmp.mean() / x.mean()).real
            tmp *= (1 / ev_mag)
            if norm((tmp - x).ravel()) < atol + rtol * n:
#            if allclose(tmp, x, rtol, atol):                
                #print (i, ev, ev_mag, norm((tmp - x).ravel())/n, atol, rtol)
                x[:] = tmp
                break            
#        else:
#            print (i, ev, ev_mag, norm((tmp - x).ravel())/norm(x.ravel()), atol, rtol)
                    
        if rescale and not abs(ev - 1) < atol:
            A1 *= 1 / sp.sqrt(ev)
            if self.sanity_checks:
                if not A1 is A2:
                    log.warning("Sanity check failed: Re-scaling with A1 <> A2!")
                if calc_l:
                    tm.eps_l_noop_inplace(x, A1, A2, tmp)
                else:
                    tm.eps_r_noop_inplace(x, A1, A2, tmp)
                ev = tmp.mean() / x.mean()
                if not abs(ev - 1) < atol:
                    log.warning("Sanity check failed: Largest ev after re-scale = %s", ev)
        
        return x, i < max_itr - 1, i
Пример #2
0
    def restore_LCF(self):
        Gm1 = sp.eye(self.D[0], dtype=self.typ) #This is actually just the number 1
        for n in xrange(1, self.N):
            self.l[n], G, Gi = tm.restore_LCF_l(self.A[n], self.l[n - 1], Gm1,
                                                zero_tol=self.zero_tol,
                                                sanity_checks=self.sanity_checks)
            Gm1 = G
        
        #Now do A[N]...
        #Apply the remaining G[N - 1] from the previous step.
        for s in xrange(self.q[self.N]):                
            self.A[self.N][s] = Gm1.dot(self.A[self.N][s])
                    
        #Now finish off
        tm.eps_l_noop_inplace(self.l[self.N - 1], self.A[self.N], self.A[self.N], out=self.l[self.N])
        
        #normalize
        GNi = 1. / sp.sqrt(self.l[self.N].squeeze().real)
        self.A[self.N] *= GNi
        self.l[self.N][:] = 1
        
        if self.sanity_checks:
            lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N], self.A[self.N])
            if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12):
                log.warning("Sanity Fail in restore_LCF!: l_N is bad / norm failure")

        #diag r
        Gi = sp.eye(self.D[self.N], dtype=self.typ)
        for n in xrange(self.N, 1, -1):
            self.r[n - 1], Gm1, Gm1_i = tm.restore_LCF_r(self.A[n], self.r[n],
                                                         Gi, self.sanity_checks)
            Gi = Gm1_i

        #Apply remaining G1i to A[1]
        for s in xrange(self.q[1]):
            self.A[1][s] = self.A[1][s].dot(Gi)

        #Deal with final, scalar r[0]
        tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0])

        if self.sanity_checks:
            if not sp.allclose(self.r[0], 1, atol=1E-12, rtol=1E-12):
                log.warning("Sanity Fail in restore_LCF!: r_0 is bad / norm failure")
                log.warning("r_0 = %s", self.r[0].squeeze().real)
            
            for n in xrange(1, self.N + 1):
                l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
                if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11):
                    log.warning("Sanity Fail in restore_LCF!: l_%u is bad (off by %g)", n, la.norm(l - self.l[n]))
                    log.warning((l - self.l[n]).diagonal().real)
Пример #3
0
    def matvec(self, v):
        x = v.reshape((self.D, self.D))

        if self.left:  #Multiplying from the left, but x is a col. vector, so use mat_dagger
            Ehx = tm.eps_l_noop_inplace(x, self.A1, self.A2, self.out)
            if self.pseudo:
                QEQhx = Ehx - self.l * m.adot(self.r, x)
                res = x - sp.exp(-1.j * self.p) * QEQhx
            else:
                res = x - sp.exp(-1.j * self.p) * Ehx
        else:
            Ex = tm.eps_r_noop_inplace(x, self.A1, self.A2, self.out)
            if self.pseudo:
                QEQx = Ex - self.r * m.adot(self.l, x)
                res = x - sp.exp(1.j * self.p) * QEQx
            else:
                res = x - sp.exp(1.j * self.p) * Ex

        return res.ravel()
Пример #4
0
    def matvec(self, v):
        x = v.reshape((self.D, self.D))

        res = self.tmp
        out = self.out
        res[:] = x

        if self.left:  # Multiplying from the left, but x is a col. vector, so use mat_dagger
            for k in xrange(len(self.A1)):
                out = tm.eps_l_noop_inplace(res, self.A1[k], self.A2[k], out)
                tmp = res
                res = out
                out = tmp

            if self.pseudo:
                out[:] = self.lL
                out *= m.adot(self.rL, x)
                res -= out
                res *= -sp.exp(-1.0j * self.p)
                res += x
            else:
                res *= -sp.exp(-1.0j * self.p)
                res += x
        else:
            for k in xrange(len(self.A1) - 1, -1, -1):
                out = tm.eps_r_noop_inplace(res, self.A1[k], self.A2[k], out)
                tmp = res
                res = out
                out = tmp

            if self.pseudo:
                out[:] = self.rL
                out *= m.adot(self.lL, x)
                res -= out
                res *= -sp.exp(1.0j * self.p)
                res += x
            else:
                res *= -sp.exp(1.0j * self.p)
                res += x

        return (
            res.copy().ravel()
        )  # apparently we can't reuse the memory we return (seems to blow up lgmres), so we make a copy
Пример #5
0
 def matvec(self, v):
     x = v.reshape((self.D, self.D))
     
     if self.left: #Multiplying from the left, but x is a col. vector, so use mat_dagger
         Ehx = tm.eps_l_noop_inplace(x, self.A1, self.A2, self.out)
         if self.pseudo:
             QEQhx = Ehx - self.l * m.adot(self.r, x)
             res = x - sp.exp(-1.j * self.p) * QEQhx
         else:
             res = x - sp.exp(-1.j * self.p) * Ehx
     else:
         Ex = tm.eps_r_noop_inplace(x, self.A1, self.A2, self.out)
         if self.pseudo:
             QEQx = Ex - self.r * m.adot(self.l, x)
             res = x - sp.exp(1.j * self.p) * QEQx
         else:
             res = x - sp.exp(1.j * self.p) * Ex
     
     return res.ravel()
Пример #6
0
    def matvec(self, v):
        x = v.reshape((self.D, self.D))
        
        res = self.tmp
        out = self.out
        res[:] = x
        
        if self.left: #Multiplying from the left, but x is a col. vector, so use mat_dagger
            for k in xrange(len(self.A1)):
                out = tm.eps_l_noop_inplace(res, self.A1[k], self.A2[k], out)
                tmp = res
                res = out
                out = tmp
                
            if self.pseudo:
                out[:] = self.lL
                out *= m.adot(self.rL, x)
                res -= out
                res *= -sp.exp(-1.j * self.p)
                res += x
            else:
                res *= -sp.exp(-1.j * self.p)
                res += x
        else:
            for k in xrange(len(self.A1) - 1, -1, -1):
                out = tm.eps_r_noop_inplace(res, self.A1[k], self.A2[k], out)
                tmp = res
                res = out
                out = tmp
                
            if self.pseudo:
                out[:] = self.rL 
                out *= m.adot(self.lL, x)
                res -= out
                res *= -sp.exp(1.j * self.p)
                res += x
            else:
                res *= -sp.exp(1.j * self.p)
                res += x

        return res.copy().ravel() #apparently we can't reuse the memory we return (seems to blow up lgmres), so we make a copy
Пример #7
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()
Пример #8
0
    def restore_LCF(self):
        Gm1 = sp.eye(self.D[0],
                     dtype=self.typ)  #This is actually just the number 1
        for n in xrange(1, self.N):
            self.l[n], G, Gi = tm.restore_LCF_l(
                self.A[n],
                self.l[n - 1],
                Gm1,
                zero_tol=self.zero_tol,
                sanity_checks=self.sanity_checks)
            Gm1 = G

        #Now do A[N]...
        #Apply the remaining G[N - 1] from the previous step.
        for s in xrange(self.q[self.N]):
            self.A[self.N][s] = Gm1.dot(self.A[self.N][s])

        #Now finish off
        tm.eps_l_noop_inplace(self.l[self.N - 1],
                              self.A[self.N],
                              self.A[self.N],
                              out=self.l[self.N])

        #normalize
        GNi = 1. / sp.sqrt(self.l[self.N].squeeze().real)
        self.A[self.N] *= GNi
        self.l[self.N][:] = 1

        if self.sanity_checks:
            lN = tm.eps_l_noop(self.l[self.N - 1], self.A[self.N],
                               self.A[self.N])
            if not sp.allclose(lN, 1, atol=1E-12, rtol=1E-12):
                log.warning(
                    "Sanity Fail in restore_LCF!: l_N is bad / norm failure")

        #diag r
        Gi = sp.eye(self.D[self.N], dtype=self.typ)
        for n in xrange(self.N, 1, -1):
            self.r[n - 1], Gm1, Gm1_i = tm.restore_LCF_r(
                self.A[n], self.r[n], Gi, self.sanity_checks)
            Gi = Gm1_i

        #Apply remaining G1i to A[1]
        for s in xrange(self.q[1]):
            self.A[1][s] = self.A[1][s].dot(Gi)

        #Deal with final, scalar r[0]
        tm.eps_r_noop_inplace(self.r[1], self.A[1], self.A[1], out=self.r[0])

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

            for n in xrange(1, self.N + 1):
                l = tm.eps_l_noop(self.l[n - 1], self.A[n], self.A[n])
                if not sp.allclose(l, self.l[n], atol=1E-11, rtol=1E-11):
                    log.warning(
                        "Sanity Fail in restore_LCF!: l_%u is bad (off by %g)",
                        n, la.norm(l - self.l[n]))
                    log.warning((l - self.l[n]).diagonal().real)
Пример #9
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()
Пример #10
0
    def _calc_lr_ARPACK(self, x, tmp, calc_l=False, A1=None, A2=None, rescale=True,
                        tol=1E-14, ncv=None, k=1):
        if A1 is None:
            A1 = self.A
        if A2 is None:
            A2 = self.A
            
        if self.D == 1:
            x.fill(1)
            if calc_l:
                ev = tm.eps_l_noop(x, A1, A2)[0, 0]
            else:
                ev = tm.eps_r_noop(x, A1, A2)[0, 0]
            
            if rescale and not abs(ev - 1) < tol:
                A1 *= 1 / sp.sqrt(ev)
            
            return x, True, 1
                        
        try:
            norm = la.get_blas_funcs("nrm2", [x])
        except (ValueError, AttributeError):
            norm = np.linalg.norm
    
        n = x.size #we will scale x so that stuff doesn't get too small
        
        #start = time.clock()
        opE = EOp(A1, A2, calc_l)
        x *= n / norm(x.ravel())
        try:
            ev, eV = las.eigs(opE, which='LM', k=k, v0=x.ravel(), tol=tol, ncv=ncv)
            conv = True
        except las.ArpackNoConvergence:
            log.warning("Reset! (l? %s)", calc_l)
            ev, eV = las.eigs(opE, which='LM', k=k, tol=tol, ncv=ncv)
            conv = True
            
        #print ev2
        #print ev2 * ev2.conj()
        ind = ev.argmax()
        ev = np.real_if_close(ev[ind])
        ev = np.asscalar(ev)
        eV = eV[:, ind]
        
        #remove any additional phase factor
        eVmean = eV.mean()
        eV *= sp.sqrt(sp.conj(eVmean) / eVmean)
        
        if eV.mean() < 0:
            eV *= -1

        eV = eV.reshape(self.D, self.D)
        
        eV *= n / norm(eV.ravel())
        
        x[:] = eV
        
        #print "splinalg: %g" % (time.clock() - start)   
        
        #print "Herm? %g" % norm((eV - m.H(eV)).ravel())
        #print "Norm of diff: %g" % norm((eV - x).ravel())
        #print "Norms: (%g, %g)" % (norm(eV.ravel()), norm(x.ravel()))
                    
        if rescale and not abs(ev - 1) < tol:
            A1 *= 1 / sp.sqrt(ev)
            if self.sanity_checks:
                if not A1 is A2:
                    log.warning("Sanity check failed: Re-scaling with A1 <> A2!")
                if calc_l:
                    tm.eps_l_noop_inplace(x, A1, A2, tmp)
                else:
                    tm.eps_r_noop_inplace(x, A1, A2, tmp)
                ev = tmp.mean() / x.mean()
                if not abs(ev - 1) < tol:
                    log.warning("Sanity check failed: Largest ev after re-scale = %s", ev)
        
        return x, conv, opE.calls