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
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)
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()
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
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
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()
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)
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()
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