def get_r(self, n, r_np1=None): """Gets an r[n], even if n < 0 or n > N + 1 """ if 0 <= n <= self.N + 1: return self.r[n] elif n > self.N + 1: return self.r[self.N + 1] else: if r_np1 is None: r_m = self.r[0] for m in reversed(xrange(n, 0)): r_m = tm.eps_r_noop(r_m, self.A[0], self.A[0]) return r_m else: return tm.eps_r_noop(r_np1, self.A[0], self.A[0])
def get_r(self, n, r_np1=None): """Gets an r[n], even if n < 0 or n > N + 1 """ if 0 <= n <= self.N + 1: return self.r[n] elif n > self.N + 1: return self.uni_r.r[(n - 1) % self.uni_r.L] else: if r_np1 is None: r_m = self.r[0] for m in (sp.arange(0, n, -1) - 1) % self.uni_l.L: r_m = tm.eps_r_noop(r_m, self.uni_l.A[m], self.uni_l.A[m]) return r_m else: m = n % self.uni_l.L return tm.eps_r_noop(r_np1, self.uni_l.A[m], self.uni_l.A[m])
def _excite_expect_2s_tp_sep(AL, AR, B, lL, rR, op, d, n1, n2): ls = [None] * (d + 1) ls[0] = lL rs = [None] * (d + 1) rs[-1] = rR As1 = [None] + [AL] * (n1 - 1) + [B] + [AR] * (d - n1 + 1) As2 = [None] + [AL] * (n2 - 1) + [B] + [AR] * (d - n2 + 1) for n in xrange(1, d): ls[n] = tm.eps_l_noop(ls[n - 1], As1[n], As2[n]) for n in xrange(d, 0, -1): rs[n - 1] = tm.eps_r_noop(rs[n], As1[n], As2[n]) Cs1 = [None] * (d + 1) for n in xrange(1, d): Cs1[n] = tm.calc_C_tp(op, As1[n], As1[n + 1]) res = [ m.adot(ls[n - 1], tm.eps_r_op_2s_C12_tp(rs[n + 1], Cs1[n], As2[n], As2[n + 1])) for n in xrange(1, d) ] return sp.array(res)
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
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
def calc_r(self, n_low=-1, n_high=-1): """Updates the r matrices using the current state parameters self.A. Implements step 5 of the TDVP algorithm or, equivalently, eqn. (41). (arXiv:1103.0936v2 [cond-mat.str-el]) """ if n_low < 0: n_low = 0 if n_high < 0: n_high = self.N - 1 for n in xrange(n_high, n_low - 1, -1): self.r[n] = tm.eps_r_noop(self.r[n + 1], self.A[n + 1], self.A[n + 1])
def f(tau, *args): if tau < 0: if use_tangvec_overlap: res = tau**2 + self.eta_sq.sum().real else: res = tau**2 + h_expect_0.real log.debug((tau, res, "punishing negative tau!")) taus.append(tau) ress.append(res) hs.append(h_expect_0.real) return res try: i = taus.index(tau) log.debug((tau, ress[i], "from stored")) return ress[i] except ValueError: for n in xrange(1, self.N + 1): if not Bs[n] is None: self.A[n] = As0[n] - tau * Bs[n] if use_tangvec_overlap: self.update(restore_CF=False) Bsg = self.calc_B(set_eta=False) res = 0 for n in xrange(1, self.N + 1): if not Bs[n] is None: res += abs(m.adot(self.l[n - 1], tm.eps_r_noop(self.r[n], Bsg[n], Bs[n]))) h_exp = self.H_expect.real else: self.calc_l() self.calc_r() self.simple_renorm() self.calc_C() h_exp = 0 if self.ham_sites == 2: for n in xrange(1, self.N): h_exp += self.expect_2s(self.ham[n], n).real else: for n in xrange(1, self.N - 1): h_exp += self.expect_3s(self.ham[n], n).real res = h_exp log.debug((tau, res, h_exp, h_exp - h_expect_0.real)) taus.append(tau) ress.append(res) hs.append(h_exp) return res
def restore_RCF(self, use_QR=True, update_l=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. It is 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) diag_l : bool Whether to put l in diagonal form (defaults to True) """ if use_QR: tm.restore_RCF_r_seq(self.A, self.r, sanity_checks=self.sanity_checks, sc_data="restore_RCF_r") else: G_n_i = sp.eye(self.D[self.N], dtype=self.typ) #This is actually just the number 1 for n in xrange(self.N, 0, -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) if self.sanity_checks: if not sp.allclose(self.r[0].A, 1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF!: r_0 is bad / norm failure") if diag_l: tm.restore_RCF_l_seq(self.A, self.l, sanity_checks=self.sanity_checks, sc_data="restore_RCF_l") if self.sanity_checks: if not sp.allclose(self.l[self.N].A, 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_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
def expect_1s_1s(self, op1, op2, d): """Computes the expectation value of two single site operators acting on two different sites. The result is < op1_n op2_n+d > with the operators acting on sites n and n + d. See expect_1s(). Requires d > 0. The state must be up-to-date -- see self.update()! Parameters ---------- op1 : ndarray or callable The first operator, acting on the first site. op2 : ndarray or callable The second operator, acting on the second site. d : int The distance (number of sites) between the two sites acted on non-trivially. Returns ------- expval : floating point number The expectation value (data type may be complex) """ assert d > 0, 'd must be greater than 1' if callable(op1): op1 = sp.vectorize(op1, otypes=[sp.complex128]) op1 = sp.fromfunction(op1, (self.q, self.q)) if callable(op2): op2 = sp.vectorize(op2, otypes=[sp.complex128]) op2 = sp.fromfunction(op2, (self.q, self.q)) r_n = tm.eps_r_op_1s(self.r, self.A, self.A, op2) for n in xrange(d - 1): r_n = tm.eps_r_noop(r_n, self.A, self.A) r_n = tm.eps_r_op_1s(r_n, self.A, self.A, op1) return m.adot(self.l, r_n)
def expect_1s_1s(self, op1, op2, n1, n2): """Computes the expectation value of two single site operators acting on two different sites. The result is < op1 op2 >. See expect_1s(). Requires n1 < n2. The state must be up-to-date -- see self.update()! Parameters ---------- op1 : ndarray or callable The first operator, acting on the first site. op2 : ndarray or callable The second operator, acting on the second site. n1 : int The site number of the first site. n2 : int The site number of the second site (must be > n1). Returns ------- expval : floating point number The expectation value (data type may be complex) """ if callable(op1): op1 = sp.vectorize(op1, otypes=[sp.complex128]) op1 = sp.fromfunction(op1, (self.q[n1], self.q[n1])) if callable(op2): op2 = sp.vectorize(op2, otypes=[sp.complex128]) op2 = sp.fromfunction(op2, (self.q[n2], self.q[n2])) r_n = tm.eps_r_op_1s(self.r[n2], self.A[n2], self.A[n2], op2) for n in reversed(xrange(n1 + 1, n2)): r_n = tm.eps_r_noop(r_n, self.A[n], self.A[n]) r_n = tm.eps_r_op_1s(r_n, self.A[n1], self.A[n1], op1) return m.adot(self.l[n1 - 1], r_n)
def matvec(self, x): self.calls += 1 #print self.calls t = self.tdvp n = self.n Gn = x.reshape((self.D[n], self.D[n])) res = self.KLn.dot(Gn) + Gn.dot(t.K[n + 1]) if n < t.N: Ap1 = sp.array([Gn.dot(As) for As in t.A[n + 1]]) AAn = tm.calc_AA(t.A[n], Ap1) Cn = tm.calc_C_mat_op_AA(t.ham[n], AAn) for s in xrange(t.q[n]): sres = tm.eps_r_noop(t.r[n + 1], Cn[s, :], t.A[n + 1]) res += t.A[n][s].conj().T.dot(t.l[n - 1].dot(sres)) return res.reshape(x.shape) * self.tau
def matvec(self, x): self.calls += 1 #print self.calls t = self.tdvp n = self.n An = x.reshape((self.q[n], self.D[n - 1], self.D[n])) if n > 1: AAnm1 = tm.calc_AA(t.A[n - 1], An) Cnm1 = tm.calc_C_mat_op_AA(t.ham[n - 1], AAnm1) else: AAnm1 = None Cnm1 = None if n < t.N: AAn = tm.calc_AA(An, t.A[n + 1]) Cn = tm.calc_C_mat_op_AA(t.ham[n], AAn) else: AAn = None Cn = None res = sp.zeros_like(An) #Assuming RCF if not Cnm1 is None: for s in xrange(t.q[n]): res[s] += tm.eps_l_noop(t.l[n - 2], t.A[n - 1], Cnm1[:, s]) res[s] += self.KLnm1.dot(An[s]) res[s] = self.lm1_i.dot(res[s]) if not Cn is None: for s in xrange(t.q[n]): res[s] += tm.eps_r_noop(t.r[n + 1], Cn[s, :], t.A[n + 1]) res[s] += An[s].dot(t.K[n + 1]) #print "en = ", (sp.inner(An.conj().ravel(), res.ravel()) # / sp.inner(An.conj().ravel(), An.ravel())) return res.reshape(x.shape) * self.tau
def expect_1s_cor(self, op1, op2, n1, n2): """Computes the correlation of two single site operators acting on two different sites. See expect_1S(). n1 must be smaller than n2. Assumes that the state is normalized. Parameters ---------- op1 : function The first operator, acting on the first site. op2 : function The second operator, acting on the second site. n1 : int The site number of the first site. n2 : int The site number of the second site (must be > n1). """ A1 = self.get_A(n1) A2 = self.get_A(n2) if callable(op1): op1 = sp.vectorize(op1, otypes=[sp.complex128]) op1 = sp.fromfunction(op1, (A1.shape[0], A1.shape[0])) if callable(op2): op2 = sp.vectorize(op2, otypes=[sp.complex128]) op2 = sp.fromfunction(op2, (A2.shape[0], A2.shape[0])) r_n = tm.eps_r_op_1s(self.get_r(n2), A2, A2, op2) for n in reversed(xrange(n1 + 1, n2)): r_n = tm.eps_r_noop(r_n, self.get_A(n), self.get_A(n)) r_n = tm.eps_r_op_1s(r_n, A1, A1, op1) return mm.adot(self.get_l(n1 - 1), r_n)
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 = x for k in xrange(len(self.A1)): Ehx = tm.eps_l_noop(Ehx, self.A1[k], self.A2[k]) if self.pseudo: QEQhx = Ehx - self.lL * m.adot(self.rL, x) res = x - sp.exp(-1.j * self.p) * QEQhx else: res = x - sp.exp(-1.j * self.p) * Ehx else: Ex = x for k in xrange(len(self.A1) - 1, -1, -1): Ex = tm.eps_r_noop(Ex, self.A1[k], self.A2[k]) if self.pseudo: QEQx = Ex - self.rL * m.adot(self.lL, x) res = x - sp.exp(1.j * self.p) * QEQx else: res = x - sp.exp(1.j * self.p) * Ex return res.ravel()
def _excite_expect_2s_tp_sep(AL, AR, B, lL, rR, op, d, n1, n2): ls = [None] * (d + 1) ls[0] = lL rs = [None] * (d + 1) rs[-1] = rR As1 = [None] + [AL] * (n1 - 1) + [B] + [AR] * (d - n1 + 1) As2 = [None] + [AL] * (n2 - 1) + [B] + [AR] * (d - n2 + 1) for n in xrange(1, d): ls[n] = tm.eps_l_noop(ls[n - 1], As1[n], As2[n]) for n in xrange(d, 0, -1): rs[n - 1] = tm.eps_r_noop(rs[n], As1[n], As2[n]) Cs1 = [None] * (d + 1) for n in xrange(1, d): Cs1[n] = tm.calc_C_tp(op, As1[n], As1[n + 1]) res = [m.adot(ls[n - 1], tm.eps_r_op_2s_C12_tp(rs[n + 1], Cs1[n], As2[n], As2[n + 1])) for n in xrange(1, d)] return sp.array(res)
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
def _calc_lr_brute(self): E = np.zeros((self.D**2, self.D**2), dtype=self.typ, order='C') for s in xrange(self.q): E += sp.kron(self.A[s], self.A[s].conj()) ev, eVL, eVR = la.eig(E, left=True, right=True) i = np.argmax(ev) self.A *= 1 / sp.sqrt(ev[i]) self.l = eVL[:,i].reshape((self.D, self.D)) self.r = eVR[:,i].reshape((self.D, self.D)) norm = m.adot(self.l, self.r) self.l *= 1 / sp.sqrt(norm) self.r *= 1 / sp.sqrt(norm) log.warning("Sledgehammer:") log.warning("Left ok?: %s", np.allclose( tm.eps_l_noop(self.l, self.A, self.A), self.l)) log.warning("Right ok?: %s", np.allclose( tm.eps_r_noop(self.r, self.A, self.A), self.r))
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)
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
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
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: V_, Vr_, Vri_, Vri_A_, C_, C_Vri_AA_, C_AAA_r_Ah_Vrih, \ C_AhAhlAA, C_AA_r_Ah_Vrih_, C_AAA_Vrh_, C_Vri_A_r_Ah_, \ C_AhlAA, C_AhlAA_conj, C_AA_Vrh, rhs10 = prereq else: C_, C_conj, V_, Vr_, Vri_, C_Vri_A_conj, C_AhlA, C_A_Vrh_, rhs10 = prereq A = tdvp.A[0] A_ = tdvp2.A[0] AA = tdvp.AA[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(Vri_[s])) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") BA_ = tm.calc_AA(B, A_) AB = tm.calc_AA(A, B) if self.ham_sites == 3: BAA_ = tm.calc_AAA_AA(BA_, A_) ABA_ = tm.calc_AAA_AA(AB, A_) AAB = tm.calc_AAA_AA(AA, B) y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') if self.ham_sites == 3: tmp = BAA_ + sp.exp(+1.j * p) * ABA_ + sp.exp(+2.j * p) * AAB res = l_sqrt.dot(tm.eps_r_op_3s_C123_AAA456( r_, tmp, C_Vri_AA_)) #1 1D, #3, #3c else: tmp = BA_ + sp.exp(+1.j * p) * AB res = l_sqrt.dot(tm.eps_r_op_2s_AA12_C34(r_, tmp, C_Vri_A_conj)) #1, #3 OK res += sp.exp(-1.j * p) * l_sqrt_i.dot(Mh.dot(rhs10)) #10 exp = sp.exp subres = sp.zeros_like(res) eye = m.eyemat(C_.shape[2], dtype=tdvp.typ) eye2 = m.eyemat(A.shape[2], dtype=tdvp.typ) if self.ham_sites == 3: subres += exp(-2.j * p) * tm.eps_l_noop(Mh, A, C_AAA_r_Ah_Vrih) #12 subres += exp(-3.j * p) * tm.eps_l_op_2s_AA12_C34( Mh, AA, C_AAA_Vrh_) #12b for s in xrange(self.q): #subres += exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_AAA_r_Ah_Vrih[s])) #12 subres += tm.eps_r_noop(B[s], C_AhAhlAA[s, :], Vr_) #2b subres += exp(-1.j * p) * tm.eps_l_noop( l.dot(B[s]), A, C_AA_r_Ah_Vrih_[s, :]) #4 subres += A[s].conj().T.dot( l.dot( tm.eps_r_op_2s_AA12_C34(eye2, AB, C_Vri_A_r_Ah_[ s, :, :]))) #2 -ive of that it should be.... subres += exp(-1.j * p) * tm.eps_l_op_2s_AA12_C34( eye2, C_AhlAA_conj[s, :, :], BA_).dot(Vr_[s].conj().T) #4b subres += exp(-2.j * p) * tm.eps_l_op_2s_AA12_C34( l.dot(B[s]), AA, C_AA_Vrh[s, :, :]) #4c subres += exp(+1.j * p) * tm.eps_r_op_2s_AA12_C34( r_.dot_left(B[s]), C_AhlAA[s, :, :], Vri_A_) #3b #for t in xrange(self.q): #subres += (C_AhAhlAA[t, s].dot(B[s]).dot(Vr_[t].conj().T)) #2b #subres += (exp(-1.j * p) * A[s].conj().T.dot(l.dot(B[t])).dot(C_AA_r_Ah_Vrih_[s, t])) #4 #subres += (exp(-3.j * p) * AA[t, s].conj().T.dot(Mh).dot(C_AAA_Vrh_[t, s])) #12b #for u in xrange(self.q): #subres += A[s].conj().T.dot(l.dot(AB[t, u]).dot(C_A_r_Ah_Vrih[s, t, u])) #2 -ive of that it should be.... #subres += (exp(+1.j * p) * C_AhlAA[t, s, s].dot(B[u]).dot(r_.dot(A_[u].conj().T)).dot(Vri_[t].conj().T)) #3b #subres += (exp(-1.j * p) * C_AhAhlA[s, t, u].dot(BA_[t, u]).dot(Vr_[s].conj().T)) #4b #subres += (exp(-2.j * p) * AA[t, s].conj().T.dot(l.dot(B[u])).dot(C_AA_Vrh[t, s, u])) #4c else: for s in xrange(self.q): #subres += C_AhlA[s, t].dot(B[s]).dot(Vr_[t].conj().T) #2 OK subres += tm.eps_r_noop(B[s], C_AhlA[s, :], Vr_) #2 #+ exp(-1.j * p) * A[t].conj().T.dot(l.dot(B[s])).dot(C_A_Vrh_[t, s]) #4 OK with 3 subres += exp(-1.j * p) * tm.eps_l_noop( l.dot(B[s]), A, C_A_Vrh_[s, :]) #4 #+ exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_[s, t])).dot(Vr_[t].conj().T)) #12 subres += exp(-2.j * p) * A[s].conj().T.dot(Mh).dot( tm.eps_r_noop(eye, C_[s, :], Vr_)) #12 res += l_sqrt_i.dot(subres) res += l_sqrt.dot(tm.eps_r_noop(K__r, B, Vri_)) #5 res += l_sqrt_i.dot(K_l.dot(tm.eps_r_noop(r__sqrt, B, V_))) #6 res += sp.exp(-1.j * p) * l_sqrt_i.dot( Mh.dot(tm.eps_r_noop(K__r, A_, Vri_))) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: tmp = sp.exp(+1.j * p) * BAA_ + sp.exp(+2.j * p) * ABA_ + sp.exp( +3.j * p) * AAB #9, #11, #11b y = y1 + tm.eps_r_op_3s_C123_AAA456(r_, tmp, C_) elif self.ham_sites == 2: tmp = sp.exp(+1.j * p) * BA_ + sp.exp(+2.j * p) * AB #9, #11 y = y1 + tm.eps_r_op_2s_AA12_C34(r_, tmp, C_conj) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res += l_sqrt.dot(tm.eps_r_noop(y_pi, A, Vri_)) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning( "Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
def _excite_correlation_1s_1s(AL, AR, B, lL, rR, op1, op2, d, g): pseudo = AL is AR BBL = pinv_1mE(tm.eps_l_noop(lL, B, B), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) B1L = pinv_1mE(tm.eps_l_noop(lL, B, AL), [AR], [AL], lL, rR, p=0, left=True, pseudo=pseudo) B2L = pinv_1mE(tm.eps_l_noop(lL, AL, B), [AL], [AR], lL, rR, p=0, left=True, pseudo=pseudo) B1B2L = pinv_1mE(tm.eps_l_noop(B1L, AR, B), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) B2B1L = pinv_1mE(tm.eps_l_noop(B2L, B, AR), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) BBR = pinv_1mE(tm.eps_r_noop(rR, B, B), [AL], [AL], lL, rR, p=0, left=False, pseudo=True) print "gauge fixing:", la.norm(tm.eps_r_noop(rR, B, AR)) res = [0.] * (d + 1) #B's on the left terms (0, 1, 2, 5) res[0] += m.adot( tm.eps_l_op_1s(BBL + B1B2L + B2B1L, AR, AR, op1.dot(op2) - g[0] * sp.eye(len(op1))), rR) res[0] += m.adot(tm.eps_l_op_1s(B1L, AR, B, op1.dot(op2)), rR) res[0] += m.adot(tm.eps_l_op_1s(B2L, B, AR, op1.dot(op2)), rR) res[0] += m.adot( tm.eps_l_op_1s(lL, B, B, op1.dot(op2) - g[0] * sp.eye(len(op1))), rR) l1 = tm.eps_l_op_1s(BBL + B1B2L + B2B1L, AR, AR, op1) l1 += tm.eps_l_op_1s(B1L, AR, B, op1) l1 += tm.eps_l_op_1s(B2L, B, AR, op1) l1 += tm.eps_l_op_1s(lL, B, B, op1) for n in xrange(1, d + 1): res[n] += m.adot(l1, tm.eps_r_op_1s(rR, AR, AR, op2)) res[n] -= 2 * g[n] if n == d: break l1 = tm.eps_l_noop(l1, AR, AR) print 1, res #Terms 3, 4, 6, 7, a ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(B1L, AR, AL, op1) + tm.eps_l_op_1s(lL, B, AL, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AR, AL) rs = [None] * (d + 1) rs[d - 1] = tm.eps_r_op_1s(rR, AR, AR, op2) for k in xrange(d - 1, 0, -1): rs[k - 1] = tm.eps_r_noop(rs[k], AR, AR) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], AR, B)) res[n] += m.adot(ls[n - 1], tm.eps_r_op_1s(rR, AR, B, op2)) print 2, res #Terms 3, 4, 6, 7, b ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(B2L, AL, AR, op1) + tm.eps_l_op_1s(lL, AL, B, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AL, AR) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], B, AR)) res[n] += m.adot(ls[n - 1], tm.eps_r_op_1s(rR, B, AR, op2)) print 3, res #Term 8 ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(lL, AL, AL, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AL, AL) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], B, B)) res[n] -= g[n] print 4, res #Terms 9 and 10 for n in xrange(2, d + 1): for k in xrange(2, n): lj = tm.eps_l_noop(ls[k - 1], AL, B) for j in xrange(k + 1, n): res[n] += m.adot(lj, tm.eps_r_noop(rs[-(n + 1):][j], B, AR)) lj = tm.eps_l_noop(lj, AL, AR) res[n] += m.adot(lj, tm.eps_r_op_1s(rR, B, AR, op2)) lj = tm.eps_l_noop(ls[k - 1], B, AL) for j in xrange(k + 1, n): res[n] += m.adot(lj, tm.eps_r_noop(rs[-(n + 1):][j], AR, B)) lj = tm.eps_l_noop(lj, AL, AR) res[n] += m.adot(lj, tm.eps_r_op_1s(rR, AR, B, op2)) print 5, res #Term 11 res[0] += m.adot( tm.eps_l_op_1s(lL, AL, AL, op1.dot(op2) - g[0] * sp.eye(len(op1))), BBR) for n in xrange(1, d + 1): res[n] += m.adot(tm.eps_l_op_1s(ls[n - 1], AL, AL, op2), BBR) res[n] -= g[n] return res
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
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 _excite_correlation_1s_1s(AL, AR, B, lL, rR, op1, op2, d, g): pseudo = AL is AR BBL = pinv_1mE(tm.eps_l_noop(lL, B, B), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) B1L = pinv_1mE(tm.eps_l_noop(lL, B, AL), [AR], [AL], lL, rR, p=0, left=True, pseudo=pseudo) B2L = pinv_1mE(tm.eps_l_noop(lL, AL, B), [AL], [AR], lL, rR, p=0, left=True, pseudo=pseudo) B1B2L = pinv_1mE(tm.eps_l_noop(B1L, AR, B), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) B2B1L = pinv_1mE(tm.eps_l_noop(B2L, B, AR), [AR], [AR], lL, rR, p=0, left=True, pseudo=True) BBR = pinv_1mE(tm.eps_r_noop(rR, B, B), [AL], [AL], lL, rR, p=0, left=False, pseudo=True) print "gauge fixing:", la.norm(tm.eps_r_noop(rR, B, AR)) res = [0.] * (d + 1) #B's on the left terms (0, 1, 2, 5) res[0] += m.adot(tm.eps_l_op_1s(BBL + B1B2L + B2B1L, AR, AR, op1.dot(op2) - g[0] * sp.eye(len(op1))), rR) res[0] += m.adot(tm.eps_l_op_1s(B1L, AR, B, op1.dot(op2)), rR) res[0] += m.adot(tm.eps_l_op_1s(B2L, B, AR, op1.dot(op2)), rR) res[0] += m.adot(tm.eps_l_op_1s(lL, B, B, op1.dot(op2) - g[0] * sp.eye(len(op1))), rR) l1 = tm.eps_l_op_1s(BBL + B1B2L + B2B1L, AR, AR, op1) l1 += tm.eps_l_op_1s(B1L, AR, B, op1) l1 += tm.eps_l_op_1s(B2L, B, AR, op1) l1 += tm.eps_l_op_1s(lL, B, B, op1) for n in xrange(1, d + 1): res[n] += m.adot(l1, tm.eps_r_op_1s(rR, AR, AR, op2)) res[n] -= 2 * g[n] if n == d: break l1 = tm.eps_l_noop(l1, AR, AR) print 1, res #Terms 3, 4, 6, 7, a ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(B1L, AR, AL, op1) + tm.eps_l_op_1s(lL, B, AL, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AR, AL) rs = [None] * (d + 1) rs[d - 1] = tm.eps_r_op_1s(rR, AR, AR, op2) for k in xrange(d - 1, 0, -1): rs[k - 1] = tm.eps_r_noop(rs[k], AR, AR) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], AR, B)) res[n] += m.adot(ls[n - 1], tm.eps_r_op_1s(rR, AR, B, op2)) print 2, res #Terms 3, 4, 6, 7, b ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(B2L, AL, AR, op1) + tm.eps_l_op_1s(lL, AL, B, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AL, AR) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], B, AR)) res[n] += m.adot(ls[n - 1], tm.eps_r_op_1s(rR, B, AR, op2)) print 3, res #Term 8 ls = [None] * (d + 1) ls[0] = tm.eps_l_op_1s(lL, AL, AL, op1) for k in xrange(1, d + 1): ls[k] = tm.eps_l_noop(ls[k - 1], AL, AL) for n in xrange(2, d + 1): for k in xrange(2, n): res[n] += m.adot(ls[k - 1], tm.eps_r_noop(rs[-(n + 1):][k], B, B)) res[n] -= g[n] print 4, res #Terms 9 and 10 for n in xrange(2, d + 1): for k in xrange(2, n): lj = tm.eps_l_noop(ls[k - 1], AL, B) for j in xrange(k + 1, n): res[n] += m.adot(lj, tm.eps_r_noop(rs[-(n + 1):][j], B, AR)) lj = tm.eps_l_noop(lj, AL, AR) res[n] += m.adot(lj, tm.eps_r_op_1s(rR, B, AR, op2)) lj = tm.eps_l_noop(ls[k - 1], B, AL) for j in xrange(k + 1, n): res[n] += m.adot(lj, tm.eps_r_noop(rs[-(n + 1):][j], AR, B)) lj = tm.eps_l_noop(lj, AL, AR) res[n] += m.adot(lj, tm.eps_r_op_1s(rR, AR, B, op2)) print 5, res #Term 11 res[0] += m.adot(tm.eps_l_op_1s(lL, AL, AL, op1.dot(op2) - g[0] * sp.eye(len(op1))), BBR) for n in xrange(1, d + 1): res[n] += m.adot(tm.eps_l_op_1s(ls[n - 1], AL, AL, op2), BBR) res[n] -= g[n] return res
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: return else: V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp = prereq A = tdvp.A[0] A_ = tdvp2.A[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(m.mmul(V_[s], r__sqrt_i))) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') res_ls = 0 res_lsi = 0 exp = sp.exp if self.ham_sites == 3: pass else: Bo1 = get_Aop(B, _ham_tp, 2, conj=False) tmp = sp.empty((B.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') tmp3 = sp.empty_like(tmp2, order='C') for al in xrange(len(Bo1)): tmp3 = m.dot_inplace(tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2), r__sqrt_i, tmp3) res_ls += tm.eps_r_noop_inplace(tmp3, Bo1[al], V_, tmp) #1 tmp3 = m.dot_inplace(tm.eps_r_noop_inplace(r_, B, A_o2c[al], tmp2), r__sqrt_i, tmp3) tmp = tm.eps_r_noop_inplace(tmp3, Ao1[al], V_, tmp) #3 tmp *= exp(+1.j * p) res_ls += tmp del(tmp) del(tmp2) del(tmp3) res_lsi += sp.exp(-1.j * p) * Mh.dot(rhs10) #10 if self.ham_sites == 3: pass else: Bo2 = get_Aop(B, _ham_tp, 3, conj=False) for al in xrange(len(AhlAo1)): res_lsi += AhlAo1[al].dot(tm.eps_r_noop(r__sqrt, Bo2[al], V_)) #2 res_lsi += exp(-1.j * p) * tm.eps_l_noop(l, Ao1c[al], B).dot(A_Vr_ho2[al]) #4 res_lsi += exp(-2.j * p) * tm.eps_l_noop(Mh, Ao1c[al], A_).dot(A_Vr_ho2[al]) #12 K__rri = m.mmul(K__r, r__sqrt_i) res_ls += tm.eps_r_noop(K__rri, B, V_) #5 res_lsi += K_l.dot(tm.eps_r_noop(r__sqrt, B, V_)) #6 res_lsi += sp.exp(-1.j * p) * Mh.dot(tm.eps_r_noop(K__rri, A_, V_)) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: pass elif self.ham_sites == 2: tmp = 0 for al in xrange(len(A_A_o12c)): tmp += sp.exp(+1.j * p) * tm.eps_r_noop(tm.eps_r_noop(r_, A_, A_A_o12c[al][1]), B, A_A_o12c[al][0]) #9 tmp += sp.exp(+2.j * p) * tm.eps_r_noop(tm.eps_r_noop(r_, B, A_A_o12c[al][1]), A, A_A_o12c[al][0]) #11 y = y1 + tmp #7, 9, 11 del(tmp) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res_ls += tm.eps_r_noop(m.mmul(y_pi, r__sqrt_i), A, V_) res = l_sqrt.dot(res_ls) res += l_sqrt_i.dot(res_lsi) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: V_, Vr_, Vri_, Vri_A_, C_, C_Vri_AA_, C_AAA_r_Ah_Vrih, \ C_AhAhlAA, C_AA_r_Ah_Vrih_, C_AAA_Vrh_, C_Vri_A_r_Ah_, \ C_AhlAA, C_AhlAA_conj, C_AA_Vrh, rhs10 = prereq else: C_, C_conj, V_, Vr_, Vri_, C_Vri_A_conj, C_AhlA, C_A_Vrh_, rhs10 = prereq A = tdvp.A[0] A_ = tdvp2.A[0] AA = tdvp.AA[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(Vri_[s])) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") BA_ = tm.calc_AA(B, A_) AB = tm.calc_AA(A, B) if self.ham_sites == 3: BAA_ = tm.calc_AAA_AA(BA_, A_) ABA_ = tm.calc_AAA_AA(AB, A_) AAB = tm.calc_AAA_AA(AA, B) y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') if self.ham_sites == 3: tmp = BAA_ + sp.exp(+1.j * p) * ABA_ + sp.exp(+2.j * p) * AAB res = l_sqrt.dot(tm.eps_r_op_3s_C123_AAA456(r_, tmp, C_Vri_AA_)) #1 1D, #3, #3c else: tmp = BA_ + sp.exp(+1.j * p) * AB res = l_sqrt.dot(tm.eps_r_op_2s_AA12_C34(r_, tmp, C_Vri_A_conj)) #1, #3 OK res += sp.exp(-1.j * p) * l_sqrt_i.dot(Mh.dot(rhs10)) #10 exp = sp.exp subres = sp.zeros_like(res) eye = m.eyemat(C_.shape[2], dtype=tdvp.typ) eye2 = m.eyemat(A.shape[2], dtype=tdvp.typ) if self.ham_sites == 3: subres += exp(-2.j * p) * tm.eps_l_noop(Mh, A, C_AAA_r_Ah_Vrih) #12 subres += exp(-3.j * p) * tm.eps_l_op_2s_AA12_C34(Mh, AA, C_AAA_Vrh_) #12b for s in xrange(self.q): #subres += exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_AAA_r_Ah_Vrih[s])) #12 subres += tm.eps_r_noop(B[s], C_AhAhlAA[s, :], Vr_) #2b subres += exp(-1.j * p) * tm.eps_l_noop(l.dot(B[s]), A, C_AA_r_Ah_Vrih_[s, :]) #4 subres += A[s].conj().T.dot(l.dot(tm.eps_r_op_2s_AA12_C34(eye2, AB, C_Vri_A_r_Ah_[s, :, :]))) #2 -ive of that it should be.... subres += exp(-1.j * p) * tm.eps_l_op_2s_AA12_C34(eye2, C_AhlAA_conj[s, :, :], BA_).dot(Vr_[s].conj().T) #4b subres += exp(-2.j * p) * tm.eps_l_op_2s_AA12_C34(l.dot(B[s]), AA, C_AA_Vrh[s, :, :]) #4c subres += exp(+1.j * p) * tm.eps_r_op_2s_AA12_C34(r_.dot_left(B[s]), C_AhlAA[s, :, :], Vri_A_) #3b #for t in xrange(self.q): #subres += (C_AhAhlAA[t, s].dot(B[s]).dot(Vr_[t].conj().T)) #2b #subres += (exp(-1.j * p) * A[s].conj().T.dot(l.dot(B[t])).dot(C_AA_r_Ah_Vrih_[s, t])) #4 #subres += (exp(-3.j * p) * AA[t, s].conj().T.dot(Mh).dot(C_AAA_Vrh_[t, s])) #12b #for u in xrange(self.q): #subres += A[s].conj().T.dot(l.dot(AB[t, u]).dot(C_A_r_Ah_Vrih[s, t, u])) #2 -ive of that it should be.... #subres += (exp(+1.j * p) * C_AhlAA[t, s, s].dot(B[u]).dot(r_.dot(A_[u].conj().T)).dot(Vri_[t].conj().T)) #3b #subres += (exp(-1.j * p) * C_AhAhlA[s, t, u].dot(BA_[t, u]).dot(Vr_[s].conj().T)) #4b #subres += (exp(-2.j * p) * AA[t, s].conj().T.dot(l.dot(B[u])).dot(C_AA_Vrh[t, s, u])) #4c else: for s in xrange(self.q): #subres += C_AhlA[s, t].dot(B[s]).dot(Vr_[t].conj().T) #2 OK subres += tm.eps_r_noop(B[s], C_AhlA[s, :], Vr_) #2 #+ exp(-1.j * p) * A[t].conj().T.dot(l.dot(B[s])).dot(C_A_Vrh_[t, s]) #4 OK with 3 subres += exp(-1.j * p) * tm.eps_l_noop(l.dot(B[s]), A, C_A_Vrh_[s, :]) #4 #+ exp(-2.j * p) * A[s].conj().T.dot(Mh.dot(C_[s, t])).dot(Vr_[t].conj().T)) #12 subres += exp(-2.j * p) * A[s].conj().T.dot(Mh).dot(tm.eps_r_noop(eye, C_[s, :], Vr_)) #12 res += l_sqrt_i.dot(subres) res += l_sqrt.dot(tm.eps_r_noop(K__r, B, Vri_)) #5 res += l_sqrt_i.dot(K_l.dot(tm.eps_r_noop(r__sqrt, B, V_))) #6 res += sp.exp(-1.j * p) * l_sqrt_i.dot(Mh.dot(tm.eps_r_noop(K__r, A_, Vri_))) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: tmp = sp.exp(+1.j * p) * BAA_ + sp.exp(+2.j * p) * ABA_ + sp.exp(+3.j * p) * AAB #9, #11, #11b y = y1 + tm.eps_r_op_3s_C123_AAA456(r_, tmp, C_) elif self.ham_sites == 2: tmp = sp.exp(+1.j * p) * BA_ + sp.exp(+2.j * p) * AB #9, #11 y = y1 + tm.eps_r_op_2s_AA12_C34(r_, tmp, C_conj) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res += l_sqrt.dot(tm.eps_r_noop(y_pi, A, Vri_)) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
def restore_CF(self, dbg=False): if dbg: self.calc_l() self.calc_r() self.simple_renorm() print "BEFORE..." h_before, h_left_before, h_right_before = self.restore_CF_dbg() print (h_left_before, h_before, h_right_before) self.uni_l.A = self.uni_l.A #.copy() #self.uni_l.l = self.uni_l.l.copy() #r_old = self.uni_l.r.copy() self.uni_l.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_l calc_lr iterations: ", (self.uni_l.itr_l, self.uni_l.itr_r) #uniform calc_lr() scales for RCF, but we have LCF, #so we have to correct the scaling here fac = self.uni_l.D / self.uni_l.l.trace().real if dbg: print "Scale l[0]: %g" % fac self.uni_l.l *= fac self.uni_l.r *= 1/fac # if self.sanity_checks: # if not sp.allclose(self.uni_l.l, self.l[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: True l[0] and l[L] mismatch!", la.norm(self.l[0] - self.uni_l.l) # # if not sp.allclose(self.uni_l.r, r_old, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad r[L]!", la.norm(r_old - self.uni_l.r) # # if not sp.allclose(self.uni_l.A, self.A[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[0] was scaled!", la.norm(self.A[0] - self.uni_l.A) #self.uni_l.l = self.l[0] #self.uni_l.r = r_old #self.uni_l.A = self.A[0] self.l[0] = self.uni_l.l self.A[0] = self.uni_l.A self.uni_r.A = self.uni_r.A #.copy() self.uni_r.r = self.uni_r.r #.copy() #l_old = self.uni_r.l.copy() self.uni_r.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_r calc_lr iterations: ", (self.uni_r.itr_l, self.uni_r.itr_r) # if self.sanity_checks: # if not sp.allclose(self.uni_r.A, self.A[self.N + 1], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[R] was scaled! ", la.norm(self.A[self.N + 1] - self.uni_r.A) # # if not sp.allclose(l_old, self.uni_r.l, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad l[R]! ", la.norm(l_old - self.uni_r.l) # # if not sp.allclose(self.r[self.N], self.uni_r.r, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: r[N] and r[R] mismatch!", la.norm(self.r[self.N] - self.uni_r.r) self.r[self.N] = self.uni_r.r self.A[self.N + 1] = self.uni_r.A self._restore_CF_ONR() nc = self.N_centre self.r[nc - 1] = tm.eps_r_noop(self.r[nc], self.A[nc], self.A[nc]) self.simple_renorm(update_lr=False) if dbg: self.calc_l() self.calc_r() print "AFTER ONR..." h_mid, h_left_mid, h_right_mid = self.restore_CF_dbg() print (h_left_mid, h_mid, h_right_mid) self._restore_CF_diag() #l[0] is identity, r_L = ? self.uni_l.A = self.A[0] self.uni_l.l = self.l[0] self.uni_l.l_before_CF = self.uni_l.l self.uni_l.r_before_CF = self.uni_l.r #r[N] is identity, l_R = ? self.uni_r.A = self.A[self.N + 1] self.uni_r.r = self.r[self.N] self.uni_r.l_before_CF = self.uni_r.l self.uni_r.r_before_CF = self.uni_r.r #Set l[N + 1] as well... self.l[self.N + 1][:] = tm.eps_l_noop(self.l[self.N], self.A[self.N + 1], self.A[self.N + 1]) if self.sanity_checks: l_n = self.l[0] for n in xrange(0, self.N + 1): l_n = tm.eps_l_noop(l_n, self.A[n], self.A[n]) if not sp.allclose(l_n, self.l[n], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: l_%u is bad" % n r_nm1 = self.r[self.N + 1] for n in reversed(xrange(1, self.N + 2)): r_nm1 = tm.eps_r_noop(r_nm1, self.A[n], self.A[n]) if not sp.allclose(r_nm1, self.r[n - 1], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: r_%u is bad" % (n - 1) if dbg: print "AFTER..." h_after, h_left_after, h_right_after = self.restore_CF_dbg() print (h_left_after, h_after, h_right_after) print h_after - h_before print (h_after.sum() - h_before.sum() + h_left_after - h_left_before + h_right_after - h_right_before)
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
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
def restore_CF(self, dbg=False): if dbg: self.calc_l() self.calc_r() self.simple_renorm() print "BEFORE..." h_before, h_left_before, h_right_before = self.restore_CF_dbg() print (h_left_before, h_before, h_right_before) self.uni_l.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_l calc_lr iterations: ", (self.uni_l.itr_l, self.uni_l.itr_r) # if self.sanity_checks: # if not sp.allclose(self.uni_l.l, self.l[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: True l[0] and l[L] mismatch!", la.norm(self.l[0] - self.uni_l.l) # # if not sp.allclose(self.uni_l.r, r_old, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad r[L]!", la.norm(r_old - self.uni_l.r) # # if not sp.allclose(self.uni_l.A, self.A[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[0] was scaled!", la.norm(self.A[0] - self.uni_l.A) self.l[0] = self.uni_l.l[-1] self.A[0] = None self.uni_r.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_r calc_lr iterations: ", (self.uni_r.itr_l, self.uni_r.itr_r) # if self.sanity_checks: # if not sp.allclose(self.uni_r.A, self.A[self.N + 1], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[R] was scaled! ", la.norm(self.A[self.N + 1] - self.uni_r.A) # # if not sp.allclose(l_old, self.uni_r.l, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad l[R]! ", la.norm(l_old - self.uni_r.l) # # if not sp.allclose(self.r[self.N], self.uni_r.r, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: r[N] and r[R] mismatch!", la.norm(self.r[self.N] - self.uni_r.r) self.r[self.N] = self.uni_r.r[-1] self.A[self.N + 1] = None self._restore_CF_ONR() nc = self.N_centre self.r[nc - 1] = tm.eps_r_noop(self.r[nc], self.A[nc], self.A[nc]) self.simple_renorm(update_lr=False) if dbg: self.calc_l() self.calc_r() print "AFTER ONR..." h_mid, h_left_mid, h_right_mid = self.restore_CF_dbg() print (h_left_mid, h_mid, h_right_mid) self._restore_CF_diag(dbg=dbg) #l[0] is identity, r_L = ? self.uni_l.l_before_CF = self.uni_l.l[-1] self.uni_l.r_before_CF = self.uni_l.r[-1] #r[N] is identity, l_R = ? self.uni_r.l_before_CF = self.uni_r.l[-1] self.uni_r.r_before_CF = self.uni_r.r[-1] #Set l[N + 1] as well... self.l[self.N + 1][:] = tm.eps_l_noop(self.l[self.N], self.uni_r.A[0], self.uni_r.A[0]) if self.sanity_checks: l_n = self.l[0] for n in xrange(1, self.N + 1): l_n = tm.eps_l_noop(l_n, self.A[n], self.A[n]) if not sp.allclose(l_n, self.l[n], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: l_%u is bad" % n r_nm1 = self.r[self.N] for n in reversed(xrange(1, self.N)): r_nm1 = tm.eps_r_noop(r_nm1, self.A[n], self.A[n]) if not sp.allclose(r_nm1, self.r[n - 1], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: r_%u is bad" % (n - 1) if dbg: print "AFTER..." h_after, h_left_after, h_right_after = self.restore_CF_dbg() print (h_left_after, h_after, h_right_after) print h_after - h_before print (h_after.sum() - h_before.sum() + h_left_after - h_left_before + h_right_after - h_right_before)
def restore_CF(self, dbg=False): if dbg: self.calc_l() self.calc_r() self.simple_renorm() print "BEFORE..." h_before, h_left_before, h_right_before = self.restore_CF_dbg() print(h_left_before, h_before, h_right_before) self.uni_l.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_l calc_lr iterations: ", (self.uni_l.itr_l, self.uni_l.itr_r) # if self.sanity_checks: # if not sp.allclose(self.uni_l.l, self.l[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: True l[0] and l[L] mismatch!", la.norm(self.l[0] - self.uni_l.l) # # if not sp.allclose(self.uni_l.r, r_old, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad r[L]!", la.norm(r_old - self.uni_l.r) # # if not sp.allclose(self.uni_l.A, self.A[0], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[0] was scaled!", la.norm(self.A[0] - self.uni_l.A) self.l[0] = self.uni_l.l[-1] self.A[0] = None self.uni_r.calc_lr() #Ensures largest ev of E=1 if dbg: print "uni_r calc_lr iterations: ", (self.uni_r.itr_l, self.uni_r.itr_r) # if self.sanity_checks: # if not sp.allclose(self.uni_r.A, self.A[self.N + 1], atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: A[R] was scaled! ", la.norm(self.A[self.N + 1] - self.uni_r.A) # # if not sp.allclose(l_old, self.uni_r.l, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: Bad l[R]! ", la.norm(l_old - self.uni_r.l) # # if not sp.allclose(self.r[self.N], self.uni_r.r, atol=1E-12, rtol=1E-12): # print "Sanity Fail in restore_CF!: r[N] and r[R] mismatch!", la.norm(self.r[self.N] - self.uni_r.r) self.r[self.N] = self.uni_r.r[-1] self.A[self.N + 1] = None self._restore_CF_ONR() nc = self.N_centre self.r[nc - 1] = tm.eps_r_noop(self.r[nc], self.A[nc], self.A[nc]) self.simple_renorm(update_lr=False) if dbg: self.calc_l() self.calc_r() print "AFTER ONR..." h_mid, h_left_mid, h_right_mid = self.restore_CF_dbg() print(h_left_mid, h_mid, h_right_mid) self._restore_CF_diag(dbg=dbg) #l[0] is identity, r_L = ? self.uni_l.l_before_CF = self.uni_l.l[-1] self.uni_l.r_before_CF = self.uni_l.r[-1] #r[N] is identity, l_R = ? self.uni_r.l_before_CF = self.uni_r.l[-1] self.uni_r.r_before_CF = self.uni_r.r[-1] #Set l[N + 1] as well... self.l[self.N + 1][:] = tm.eps_l_noop(self.l[self.N], self.uni_r.A[0], self.uni_r.A[0]) if self.sanity_checks: l_n = self.l[0] for n in xrange(1, self.N + 1): l_n = tm.eps_l_noop(l_n, self.A[n], self.A[n]) if not sp.allclose(l_n, self.l[n], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: l_%u is bad" % n r_nm1 = self.r[self.N] for n in reversed(xrange(1, self.N)): r_nm1 = tm.eps_r_noop(r_nm1, self.A[n], self.A[n]) if not sp.allclose( r_nm1, self.r[n - 1], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_CF!: r_%u is bad" % (n - 1) if dbg: print "AFTER..." h_after, h_left_after, h_right_after = self.restore_CF_dbg() print(h_left_after, h_after, h_right_after) print h_after - h_before print(h_after.sum() - h_before.sum() + h_left_after - h_left_before + h_right_after - h_right_before)
def calc_BHB(self, x, p, tdvp, tdvp2, prereq, M_prev=None, y_pi_prev=None, pinv_solver=None): if pinv_solver is None: pinv_solver = las.gmres if self.ham_sites == 3: return else: V_, AhlAo1, A_o2c, Ao1, Ao1c, A_Vr_ho2, A_A_o12c, rhs10, _ham_tp = prereq A = tdvp.A[0] A_ = tdvp2.A[0] l = tdvp.l[0] r_ = tdvp2.r[0] l_sqrt = tdvp.l_sqrt[0] l_sqrt_i = tdvp.l_sqrt_i[0] r__sqrt = tdvp2.r_sqrt[0] r__sqrt_i = tdvp2.r_sqrt_i[0] K__r = tdvp2.K[0] K_l = tdvp.K_left[0] pseudo = tdvp2 is tdvp B = tdvp2.get_B_from_x(x, tdvp2.Vsh[0], l_sqrt_i, r__sqrt_i) #Skip zeros due to rank-deficiency if la.norm(B) == 0: return sp.zeros_like(x), M_prev, y_pi_prev if self.sanity_checks: tst = tm.eps_r_noop(r_, B, A_) if not la.norm(tst) > self.sanity_tol: log.warning("Sanity check failed: Gauge-fixing violation! " + str(la.norm(tst))) if self.sanity_checks: B2 = np.zeros_like(B) for s in xrange(self.q): B2[s] = l_sqrt_i.dot(x.dot(m.mmul(V_[s], r__sqrt_i))) if la.norm(B - B2) / la.norm(B) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad Vri!") y = tm.eps_l_noop(l, B, A) # if pseudo: # y = y - m.adot(r_, y) * l #should just = y due to gauge-fixing M = pinv_1mE(y, [A_], [A], l, r_, p=-p, left=True, pseudo=pseudo, out=M_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='M') #print m.adot(r, M) if self.sanity_checks: y2 = M - sp.exp(+1.j * p) * tm.eps_l_noop(M, A_, A) norm = la.norm(y.ravel()) if norm == 0: norm = 1 tst = la.norm(y - y2) / norm if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad M. Off by: %g", tst) # if pseudo: # M = M - l * m.adot(r_, M) Mh = M.conj().T.copy(order='C') res_ls = 0 res_lsi = 0 exp = sp.exp if self.ham_sites == 3: pass else: Bo1 = get_Aop(B, _ham_tp, 2, conj=False) tmp = sp.empty((B.shape[1], V_.shape[1]), dtype=A.dtype, order='C') tmp2 = sp.empty((A_.shape[1], A_o2c[0].shape[1]), dtype=A.dtype, order='C') tmp3 = sp.empty_like(tmp2, order='C') for al in xrange(len(Bo1)): tmp3 = m.dot_inplace( tm.eps_r_noop_inplace(r_, A_, A_o2c[al], tmp2), r__sqrt_i, tmp3) res_ls += tm.eps_r_noop_inplace(tmp3, Bo1[al], V_, tmp) #1 tmp3 = m.dot_inplace( tm.eps_r_noop_inplace(r_, B, A_o2c[al], tmp2), r__sqrt_i, tmp3) tmp = tm.eps_r_noop_inplace(tmp3, Ao1[al], V_, tmp) #3 tmp *= exp(+1.j * p) res_ls += tmp del (tmp) del (tmp2) del (tmp3) res_lsi += sp.exp(-1.j * p) * Mh.dot(rhs10) #10 if self.ham_sites == 3: pass else: Bo2 = get_Aop(B, _ham_tp, 3, conj=False) for al in xrange(len(AhlAo1)): res_lsi += AhlAo1[al].dot(tm.eps_r_noop(r__sqrt, Bo2[al], V_)) #2 res_lsi += exp(-1.j * p) * tm.eps_l_noop(l, Ao1c[al], B).dot( A_Vr_ho2[al]) #4 res_lsi += exp(-2.j * p) * tm.eps_l_noop(Mh, Ao1c[al], A_).dot( A_Vr_ho2[al]) #12 K__rri = m.mmul(K__r, r__sqrt_i) res_ls += tm.eps_r_noop(K__rri, B, V_) #5 res_lsi += K_l.dot(tm.eps_r_noop(r__sqrt, B, V_)) #6 res_lsi += sp.exp(-1.j * p) * Mh.dot(tm.eps_r_noop(K__rri, A_, V_)) #8 y1 = sp.exp(+1.j * p) * tm.eps_r_noop(K__r, B, A_) #7 if self.ham_sites == 3: pass elif self.ham_sites == 2: tmp = 0 for al in xrange(len(A_A_o12c)): tmp += sp.exp(+1.j * p) * tm.eps_r_noop( tm.eps_r_noop(r_, A_, A_A_o12c[al][1]), B, A_A_o12c[al][0]) #9 tmp += sp.exp(+2.j * p) * tm.eps_r_noop( tm.eps_r_noop(r_, B, A_A_o12c[al][1]), A, A_A_o12c[al][0]) #11 y = y1 + tmp #7, 9, 11 del (tmp) if pseudo: y = y - m.adot(l, y) * r_ y_pi = pinv_1mE(y, [A], [A_], l, r_, p=p, left=False, pseudo=pseudo, out=y_pi_prev, tol=self.pinv_tol, solver=pinv_solver, use_CUDA=self.pinv_CUDA, CUDA_use_batch=self.pinv_CUDA_batch, sanity_checks=self.sanity_checks, sc_data='y_pi') #print m.adot(l, y_pi) if self.sanity_checks: z = y_pi - sp.exp(+1.j * p) * tm.eps_r_noop(y_pi, A, A_) tst = la.norm((y - z).ravel()) / la.norm(y.ravel()) if tst > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! Bad x_pi. Off by: %g", tst) res_ls += tm.eps_r_noop(m.mmul(y_pi, r__sqrt_i), A, V_) res = l_sqrt.dot(res_ls) res += l_sqrt_i.dot(res_lsi) if self.sanity_checks: expval = m.adot(x, res) / m.adot(x, x) #print "expval = " + str(expval) if expval < -self.sanity_tol: log.warning( "Sanity Fail in calc_BHB! H is not pos. semi-definite (%s)", expval) if abs(expval.imag) > self.sanity_tol: log.warning("Sanity Fail in calc_BHB! H is not Hermitian (%s)", expval) return res, M, y_pi
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)
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()