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