def _update_after_truncate(self, n_last_trunc, old_l, n_first_trunc, old_r): if self.canonical_form == 'right': self.r[0][0, 0] = 1 for n in xrange(1, self.N): self.l[n] = m.simple_diag_matrix(old_l[n].diag[-self.D[n]:], dtype=self.typ) self.l[self.N][0, 0] = 1 for n in xrange(self.N - 1, n_last_trunc - 1, -1): self.r[n] = m.eyemat(self.D[n], dtype=self.typ) self.calc_r(n_high=n_last_trunc - 1) else: self.l[0][0, 0] = 1 for n in xrange(1, self.N): self.r[n] = m.simple_diag_matrix(old_r[n].diag[-self.D[n]:], dtype=self.typ) self.r[0][0, 0] = 1 for n in xrange(1, n_first_trunc): self.l[n] = m.eyemat(self.D[n], dtype=self.typ) self.calc_l(n_low=n_first_trunc) self.simple_renorm()
def _update_after_truncate(self, n_last_trunc, old_l, n_first_trunc, old_r): if self.canonical_form == 'right': self.r[0][0, 0] = 1 for n in xrange(1, self.N): self.l[n] = m.simple_diag_matrix(old_l[n].diag[-self.D[n]:], dtype=self.typ) self.l[self.N][0, 0] = 1 for n in xrange(self.N - 1, n_last_trunc - 1, - 1): self.r[n] = m.eyemat(self.D[n], dtype=self.typ) self.calc_r(n_high=n_last_trunc - 1) else: self.l[0][0, 0] = 1 for n in xrange(1, self.N): self.r[n] = m.simple_diag_matrix(old_r[n].diag[-self.D[n]:], dtype=self.typ) self.r[0][0, 0] = 1 for n in xrange(1, n_first_trunc): self.l[n] = m.eyemat(self.D[n], dtype=self.typ) self.calc_l(n_low=n_first_trunc) self.simple_renorm()
def restore_LCF_r(A, r, Gi, sanity_checks=False): if Gi is None: x = r else: x = Gi.dot(r.dot(Gi.conj().T)) M = eps_r_noop(x, A, A) ev, EV = la.eigh(M) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all(ev == np.sort(ev)), "unexpected eigenvalue ordering" rm1 = mm.simple_diag_matrix(ev, dtype=A.dtype) Gm1 = EV.conj().T if Gi is None: Gi = EV #for left uniform case r = rm1 #for sanity check for s in xrange(A.shape[0]): A[s] = Gm1.dot(A[s].dot(Gi)) if sanity_checks: rm1_ = eps_r_noop(r, A, A) if not sp.allclose(rm1_, rm1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF_r!: r is bad!") log.warning(la.norm(rm1_ - rm1)) Gm1_i = EV return rm1, Gm1, Gm1_i
def restore_LCF_r(A, r, Gi, sanity_checks=False): if Gi is None: x = r else: x = Gi.dot(r.dot(Gi.conj().T)) M = eps_r_noop(x, A, A) ev, EV = la.eigh( M) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all(ev == np.sort(ev)), "unexpected eigenvalue ordering" rm1 = mm.simple_diag_matrix(ev, dtype=A.dtype) Gm1 = EV.conj().T if Gi is None: Gi = EV #for left uniform case r = rm1 #for sanity check for s in xrange(A.shape[0]): A[s] = Gm1.dot(A[s].dot(Gi)) if sanity_checks: rm1_ = eps_r_noop(r, A, A) if not sp.allclose(rm1_, rm1, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF_r!: r is bad!") log.warning(la.norm(rm1_ - rm1)) Gm1_i = EV return rm1, Gm1, Gm1_i
def calc_BB_2s(Y, Vlh, Vrh_p1, l_si_m1, r_si_p1, dD_max=16, sv_tol=1E-14): try: U, sv, Vh = la.svd(Y) except la.LinAlgError: return None, None, 0 dDn = min(sp.count_nonzero(sv > sv_tol), dD_max) sv = mm.simple_diag_matrix(sv[:dDn]) ss = sv.sqrt() Z1 = ss.dot_left(U[:, :dDn]) Z2 = ss.dot(Vh[:dDn, :]) BB12n = sp.zeros((Vlh.shape[0], l_si_m1.shape[0], dDn), dtype=Y.dtype) for s in xrange(Vlh.shape[0]): BB12n[s] = l_si_m1.dot(Vlh[s].conj().T).dot(Z1) BB21np1 = sp.zeros((Vrh_p1.shape[0], dDn, Vrh_p1.shape[1]), dtype=Y.dtype) try: for s in xrange(Vrh_p1.shape[0]): BB21np1[s] = r_si_p1.dot_left(Z2.dot(Vrh_p1[s].conj().T)) except AttributeError: for s in xrange(Vrh_p1.shape[0]): BB21np1[s] = Z2.dot(Vrh_p1[s].conj().T).dot(r_si_p1) return BB12n, BB21np1, dDn
def restore_LCF_l(A, lm1, Gm1, sanity_checks=False, zero_tol=1E-15): if Gm1 is None: GhGm1 = lm1 else: GhGm1 = Gm1.conj().T.dot(lm1.dot(Gm1)) M = eps_l_noop(GhGm1, A, A) G, Gi, new_D = herm_fac_with_inv(M, zero_tol=zero_tol, return_rank=True, sanity_checks=sanity_checks) if Gm1 is None: Gm1 = G if sanity_checks: if new_D == A.shape[2]: eye = sp.eye(A.shape[2]) else: eye = mm.simple_diag_matrix(np.append(np.zeros(A.shape[2] - new_D), np.ones(new_D)), dtype=A.dtype) if not sp.allclose(G.dot(Gi), eye, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_LCF_l!: Bad GT!") for s in xrange(A.shape[0]): A[s] = Gm1.dot(A[s]).dot(Gi) if new_D == A.shape[2]: l = mm.eyemat(A.shape[2], A.dtype) else: l = mm.simple_diag_matrix(np.append(np.zeros(A.shape[2] - new_D), np.ones(new_D)), dtype=A.dtype) if sanity_checks: lm1_ = mm.eyemat(A.shape[1], A.dtype) l_ = eps_l_noop(lm1_, A, A) if not sp.allclose(l_, l.A, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_LCF_l!: l is bad") log.warning(la.norm(l_ - l)) return l, G, Gi
def truncate(self, newD, update=True): assert newD < self.D, 'new bond-dimension must be smaller!' tmp_A = self.A tmp_l = self.l.diag self._init_arrays(newD, self.q) if self.symm_gauge: self.l = m.simple_diag_matrix(tmp_l[:self.D], dtype=self.typ) self.r = m.simple_diag_matrix(tmp_l[:self.D], dtype=self.typ) self.A = tmp_A[:, :self.D, :self.D] else: self.l = m.simple_diag_matrix(tmp_l[-self.D:], dtype=self.typ) self.r = m.eyemat(self.D, dtype=self.typ) self.A = tmp_A[:, -self.D:, -self.D:] self.l_before_CF = self.l.A self.r_before_CF = self.r.A if update: self.update()
def restore_RCF_l(self): G_nm1 = None l_nm1 = self.l[0] for n in xrange(self.N + 1): if n == 0: x = l_nm1 else: x = mm.mmul(mm.H(G_nm1), l_nm1, G_nm1) M = self.eps_l(n, x) ev, EV = la.eigh(M) self.l[n] = mm.simple_diag_matrix(ev, dtype=self.typ) G_n_i = EV if n == 0: G_nm1 = mm.H(EV) #for left uniform case l_nm1 = self.l[n] #for sanity check self.u_gnd_l.r = mm.mmul(G_nm1, self.u_gnd_l.r, G_n_i) #since r is not eye for s in xrange(self.q[n]): self.A[n][s] = mm.mmul(G_nm1, self.A[n][s], G_n_i) if self.sanity_checks: l = self.eps_l(n, l_nm1) if not sp.allclose(l, self.l[n], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF_l!: l_%u is bad" % n print la.norm(l - self.l[n]) G_nm1 = mm.H(EV) l_nm1 = self.l[n] if self.sanity_checks: if not sp.allclose(sp.dot(G_nm1, G_n_i), sp.eye(G_n_i.shape[0]), atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF_l!: Bad GT for l_%u" % n #Now G_nm1 = G_N G_nm1_i = mm.H(G_nm1) for s in xrange(self.q[self.N + 1]): self.A[self.N + 1][s] = mm.mmul(G_nm1, self.A[self.N + 1][s], G_nm1_i) ##This should not be necessary if G_N is really unitary #self.r[self.N] = mm.mmul(G_nm1, self.r[self.N], mm.H(G_nm1)) #self.r[self.N + 1] = self.r[self.N] self.u_gnd_r.l[:] = mm.mmul(mm.H(G_nm1_i), self.u_gnd_r.l, G_nm1_i) self.S_hc = sp.zeros((self.N), dtype=sp.complex128) for n in xrange(1, self.N + 1): self.S_hc[n-1] = -sp.sum(self.l[n].diag * sp.log2(self.l[n].diag))
def restore_SCF(self): X = la.cholesky(self.r, lower=True) Y = la.cholesky(self.l, lower=False) 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, m.invtr(X, lower=True)) g_i = m.mmul(m.invtr(Y, lower=False), 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)): print "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): print "Sanity check failed: Restorce_SCF, left failed!" if not np.allclose(Sfull, r): print "Sanity check failed: Restorce_SCF, right failed!" l = self.eps_l(Sfull) r = self.eps_r(Sfull) if not np.allclose(Sfull, l, rtol=self.itr_rtol*self.check_fac, atol=self.itr_atol*self.check_fac): print "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): print "Sanity check failed: Restorce_SCF, right bad!" self.l = S self.r = S
def herm_fac_with_inv(A, lower=False, zero_tol=1E-15, return_rank=False, calc_inv=True, force_evd=False, sanity_checks=False, sc_data=''): """Factorizes a Hermitian matrix using either Cholesky or eigenvalue decomposition. Decomposes a Hermitian A as A = X*X or, if lower == True, A = XX*. Tries Cholesky first by default, then falls back to EVD if the matrix is not positive-definite. If Cholesky decomposition is used, X is upper (or lower) triangular. For the EVD decomposition, the inverse becomes a pseudo-inverse and all eigenvalues below the zero-tolerance are set to zero. Parameters ---------- A : ndarray The Hermitian matrix to be factorized. lower : bool Refers to Cholesky factorization. If True, factorize as A = XX*, otherwise as A = X*X zero_tol : float Tolerance for detection of zeros in EVD case. return_rank : bool Whether to return the rank of A. The detected rank is affected by zero_tol. calc_inv : bool Whether to calculate (and return) the inverse of the factor. force_evd : bool Whether to force eigenvalue instead of Cholesky decomposition. sanity_checks : bool Whether to perform soem basic sanity checks. """ if not force_evd: try: x = la.cholesky(A, lower=lower) if calc_inv: xi = mm.invtr(x, lower=lower) else: xi = None nonzeros = A.shape[0] except sp.linalg.LinAlgError: #this usually means a is not pos. def. force_evd = True if force_evd: ev, EV = la.eigh(A, turbo=True) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all(ev == np.sort(ev)), "Sanity fail in herm_fac_with_inv(): Unexpected eigenvalue ordering" if ev.min() < -zero_tol: log.warning("Sanity fail in herm_fac_with_inv(): Discarding negative eigenvalues! %s %s", ev.min(), sc_data) nonzeros = np.count_nonzero(ev > zero_tol) ev_sq = sp.zeros_like(ev, dtype=A.dtype) ev_sq[-nonzeros:] = sp.sqrt(ev[-nonzeros:]) ev_sq = mm.simple_diag_matrix(ev_sq, dtype=A.dtype) if calc_inv: #Replace almost-zero values with zero and perform a pseudo-inverse ev_sq_i = sp.zeros_like(ev, dtype=A.dtype) ev_sq_i[-nonzeros:] = 1. / ev_sq[-nonzeros:] ev_sq_i = mm.simple_diag_matrix(ev_sq_i, dtype=A.dtype) xi = None if lower: x = ev_sq.dot_left(EV) if calc_inv: xi = ev_sq_i.dot(EV.conj().T) else: x = ev_sq.dot(EV.conj().T) if calc_inv: xi = ev_sq_i.dot_left(EV) if sanity_checks: if not sp.allclose(A, A.conj().T, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): A is not Hermitian! %s %s", la.norm(A - A.conj().T), sc_data) eye = sp.zeros((A.shape[0]), dtype=A.dtype) eye[-nonzeros:] = 1 eye = mm.simple_diag_matrix(eye) if lower: if calc_inv: if not sp.allclose(xi.dot(x), eye, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad left inverse! %s %s", la.norm(xi.dot(x) - eye), sc_data) if not sp.allclose(xi.dot(A).dot(xi.conj().T), eye, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad A inverse! %s %s", la.norm(xi.conj().T.dot(A).dot(xi) - eye), sc_data) if not sp.allclose(x.dot(x.conj().T), A, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad decomp! %s %s", la.norm(x.dot(x.conj().T) - A), sc_data) else: if calc_inv: if not sp.allclose(x.dot(xi), eye, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad right inverse! %s %s", la.norm(x.dot(xi) - eye), sc_data) if not sp.allclose(xi.conj().T.dot(A).dot(xi), eye, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad A inverse! %s %s", la.norm(xi.conj().T.dot(A).dot(xi) - eye), sc_data) if not sp.allclose(x.conj().T.dot(x), A, atol=1E-13, rtol=1E-13): log.warning("Sanity fail in herm_fac_with_inv(): Bad decomp! %s %s", la.norm(x.conj().T.dot(x) - A), sc_data) if calc_inv: if return_rank: return x, xi, nonzeros else: return x, xi else: if return_rank: return x, nonzeros else: return x
def restore_RCF_l(A, lm1, Gm1, sanity_checks=False): """Transforms a single A[n] to obtain diagonal l[n]. Applied after restore_RCF_r(), this completes the full canonical form of sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This function must be called for each n in turn, starting at 1, passing the gauge transformation matrix from the previous step as an argument. Finds a G[n] such that orthonormalization is fulfilled for n. The diagonal entries of l[n] are sorted in ascending order (for example l[n] = diag([0, 0, 0.1, 0.2, ...])). Parameters ---------- A : ndarray The parameter tensor for the nth site A[n]. lm1 : ndarray or object with array interface The matrix l[n - 1]. Gm1 : ndarray The gauge transform matrix for site n obtained in the previous step (for n - 1). sanity_checks : bool (False) Whether to perform additional sanity checks. Returns ------- l : ndarray or simple_diag_matrix The new, diagonal matrix l[n]. G : ndarray The gauge transformation matrix for site n. G_i : ndarray Inverse of G. """ if Gm1 is None: x = lm1 else: x = Gm1.conj().T.dot(lm1.dot(Gm1)) M = eps_l_noop(x, A, A) ev, EV = la.eigh( M) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all(ev == np.sort(ev)), "unexpected eigenvalue ordering" l = mm.simple_diag_matrix(ev, dtype=A.dtype) G_i = EV if Gm1 is None: Gm1 = EV.conj().T #for left uniform case lm1 = l #for sanity check for s in xrange(A.shape[0]): A[s] = Gm1.dot(A[s].dot(G_i)) if sanity_checks: l_ = eps_l_noop(lm1, A, A) if not sp.allclose(l_, l, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF_l!: l is bad!") log.warning(la.norm(l_ - l)) G = EV.conj().T return l, G, G_i
def restore_RCF_r(A, r, G_n_i, zero_tol=1E-15, sanity_checks=False, sc_data=''): """Transforms a single A[n] to obtain r[n - 1] = eye(D). Implements the condition for right-orthonormalization from sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This function must be called for each n in turn, starting at N + 1, passing the gauge transformation matrix from the previous step as an argument. Finds a G[n-1] such that orthonormalization is fulfilled for n. If rank-deficiency is encountered, the result fulfills the orthonormality condition in the occupied subspace with the zeros at the top-left (for example r = diag([0, 0, 1, 1, 1, 1, 1])). Parameters ---------- A : ndarray The parameter tensor for the nth site A[n]. r : ndarray or object with array interface The matrix r[n]. G_n_i : ndarray The inverse gauge transform matrix for site n obtained in the previous step (for n + 1). sanity_checks : bool (False) Whether to perform additional sanity checks. zero_tol : float Tolerance for detecting zeros. Returns ------- r_nm1 : ndarray or simple_diag_matrix or eyemat The new matrix r[n - 1]. G_nm1 : ndarray The gauge transformation matrix for the site n - 1. G_n_m1_i : ndarray The inverse gauge transformation matrix for the site n - 1. """ if G_n_i is None: GGh_n_i = r else: GGh_n_i = G_n_i.dot(r.dot(G_n_i.conj().T)) M = eps_r_noop(GGh_n_i, A, A) X, Xi, new_D = herm_fac_with_inv(M, zero_tol=zero_tol, return_rank=True, sanity_checks=sanity_checks) G_nm1 = Xi.conj().T G_nm1_i = X.conj().T if G_n_i is None: G_n_i = G_nm1_i if sanity_checks: #GiG may not be equal to eye in the case of rank-deficiency, #but the rest should lie in the null space of A. GiG = G_nm1_i.dot(G_nm1) As = np.sum(A, axis=0) if not sp.allclose( GiG.dot(As).dot(G_n_i), As.dot(G_n_i), atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_RCF_r!: Bad GT! %s %s", la.norm(GiG.dot(As).dot(G_n_i) - As.dot(G_n_i)), sc_data) for s in xrange(A.shape[0]): A[s] = G_nm1.dot(A[s]).dot(G_n_i) if new_D == A.shape[1]: r_nm1 = mm.eyemat(A.shape[1], A.dtype) else: r_nm1 = sp.zeros((A.shape[1]), dtype=A.dtype) r_nm1[-new_D:] = 1 r_nm1 = mm.simple_diag_matrix(r_nm1, dtype=A.dtype) if sanity_checks: r_nm1_ = G_nm1.dot(M).dot(G_nm1.conj().T) if not sp.allclose(r_nm1_, r_nm1.A, atol=1E-13, rtol=1E-13): log.warning( "Sanity Fail in restore_RCF_r!: r != g old_r gH! %s %s", la.norm(r_nm1_ - r_nm1), sc_data) r_nm1_ = eps_r_noop(r, A, A) if not sp.allclose(r_nm1_, r_nm1.A, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_RCF_r!: r is bad! %s %s", la.norm(r_nm1_ - r_nm1), sc_data) return r_nm1, G_nm1, G_nm1_i
def herm_fac_with_inv(A, lower=False, zero_tol=1E-15, return_rank=False, calc_inv=True, force_evd=False, sanity_checks=False, sc_data=''): """Factorizes a Hermitian matrix using either Cholesky or eigenvalue decomposition. Decomposes a Hermitian A as A = X*X or, if lower == True, A = XX*. Tries Cholesky first by default, then falls back to EVD if the matrix is not positive-definite. If Cholesky decomposition is used, X is upper (or lower) triangular. For the EVD decomposition, the inverse becomes a pseudo-inverse and all eigenvalues below the zero-tolerance are set to zero. Parameters ---------- A : ndarray The Hermitian matrix to be factorized. lower : bool Refers to Cholesky factorization. If True, factorize as A = XX*, otherwise as A = X*X zero_tol : float Tolerance for detection of zeros in EVD case. return_rank : bool Whether to return the rank of A. The detected rank is affected by zero_tol. calc_inv : bool Whether to calculate (and return) the inverse of the factor. force_evd : bool Whether to force eigenvalue instead of Cholesky decomposition. sanity_checks : bool Whether to perform soem basic sanity checks. """ if not force_evd: try: x = la.cholesky(A, lower=lower) if calc_inv: xi = mm.invtr(x, lower=lower) else: xi = None nonzeros = A.shape[0] except sp.linalg.LinAlgError: #this usually means a is not pos. def. force_evd = True if force_evd: ev, EV = la.eigh( A, turbo=True ) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all( ev == np.sort(ev) ), "Sanity fail in herm_fac_with_inv(): Unexpected eigenvalue ordering" if ev.min() < -zero_tol: log.warning( "Sanity fail in herm_fac_with_inv(): Discarding negative eigenvalues! %s %s", ev.min(), sc_data) nonzeros = np.count_nonzero(ev > zero_tol) ev_sq = sp.zeros_like(ev, dtype=A.dtype) ev_sq[-nonzeros:] = sp.sqrt(ev[-nonzeros:]) ev_sq = mm.simple_diag_matrix(ev_sq, dtype=A.dtype) if calc_inv: #Replace almost-zero values with zero and perform a pseudo-inverse ev_sq_i = sp.zeros_like(ev, dtype=A.dtype) ev_sq_i[-nonzeros:] = 1. / ev_sq[-nonzeros:] ev_sq_i = mm.simple_diag_matrix(ev_sq_i, dtype=A.dtype) xi = None if lower: x = ev_sq.dot_left(EV) if calc_inv: xi = ev_sq_i.dot(EV.conj().T) else: x = ev_sq.dot(EV.conj().T) if calc_inv: xi = ev_sq_i.dot_left(EV) if sanity_checks: if not sp.allclose(A, A.conj().T, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): A is not Hermitian! %s %s", la.norm(A - A.conj().T), sc_data) eye = sp.zeros((A.shape[0]), dtype=A.dtype) eye[-nonzeros:] = 1 eye = mm.simple_diag_matrix(eye) if lower: if calc_inv: if not sp.allclose(xi.dot(x), eye, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad left inverse! %s %s", la.norm(xi.dot(x) - eye), sc_data) if not sp.allclose( xi.dot(A).dot( xi.conj().T), eye, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad A inverse! %s %s", la.norm(xi.conj().T.dot(A).dot(xi) - eye), sc_data) if not sp.allclose(x.dot(x.conj().T), A, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad decomp! %s %s", la.norm(x.dot(x.conj().T) - A), sc_data) else: if calc_inv: if not sp.allclose(x.dot(xi), eye, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad right inverse! %s %s", la.norm(x.dot(xi) - eye), sc_data) if not sp.allclose( xi.conj().T.dot(A).dot(xi), eye, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad A inverse! %s %s", la.norm(xi.conj().T.dot(A).dot(xi) - eye), sc_data) if not sp.allclose(x.conj().T.dot(x), A, atol=1E-13, rtol=1E-13): log.warning( "Sanity fail in herm_fac_with_inv(): Bad decomp! %s %s", la.norm(x.conj().T.dot(x) - A), sc_data) if calc_inv: if return_rank: return x, xi, nonzeros else: return x, xi else: if return_rank: return x, nonzeros else: return x
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 herm_sqrt_inv(x, zero_tol=1E-15, sanity_checks=False, return_rank=False, sc_data=''): if isinstance(x, mm.eyemat): x_sqrt = x x_sqrt_i = x rank = x.shape[0] else: try: ev = x.diag #simple_diag_matrix EV = None except AttributeError: ev, EV = la.eigh(x) zeros = ev <= zero_tol #throw away negative results too! ev_sqrt = sp.sqrt(ev) err = sp.seterr(divide='ignore', invalid='ignore') try: ev_sqrt_i = 1 / ev_sqrt ev_sqrt[zeros] = 0 ev_sqrt_i[zeros] = 0 finally: sp.seterr(divide=err['divide'], invalid=err['invalid']) if EV is None: x_sqrt = mm.simple_diag_matrix(ev_sqrt, dtype=x.dtype) x_sqrt_i = mm.simple_diag_matrix(ev_sqrt_i, dtype=x.dtype) else: B = mm.mmul_diag(ev_sqrt, EV.conj().T) x_sqrt = EV.dot(B) B = mm.mmul_diag(ev_sqrt_i, EV.conj().T) x_sqrt_i = EV.dot(B) rank = x.shape[0] - np.count_nonzero(zeros) if sanity_checks: if ev.min() < -zero_tol: log.warning( "Sanity Fail in herm_sqrt_inv(): Throwing away negative eigenvalues! %s %s", ev.min(), sc_data) if not np.allclose(x_sqrt.dot(x_sqrt), x): log.warning( "Sanity Fail in herm_sqrt_inv(): x_sqrt is bad! %s %s", la.norm(x_sqrt.dot(x_sqrt) - x), sc_data) if EV is None: nulls = sp.zeros(x.shape[0]) nulls[zeros] = 1 nulls = sp.diag(nulls) else: #if we did an EVD then we use the eigenvectors nulls = EV.copy() nulls[:, sp.invert(zeros)] = 0 nulls = nulls.dot(nulls.conj().T) eye = np.eye(x.shape[0]) if not np.allclose(x_sqrt.dot(x_sqrt_i), eye - nulls): log.warning( "Sanity Fail in herm_sqrt_inv(): x_sqrt_i is bad! %s %s", la.norm(x_sqrt.dot(x_sqrt_i) - eye + nulls), sc_data) if return_rank: return x_sqrt, x_sqrt_i, rank else: return x_sqrt, x_sqrt_i
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 herm_sqrt_inv(x, zero_tol=1E-15, sanity_checks=False, return_rank=False, sc_data=''): if isinstance(x, mm.eyemat): x_sqrt = x x_sqrt_i = x rank = x.shape[0] else: try: ev = x.diag #simple_diag_matrix EV = None except AttributeError: ev, EV = la.eigh(x) zeros = ev <= zero_tol #throw away negative results too! ev_sqrt = sp.sqrt(ev) err = sp.seterr(divide='ignore', invalid='ignore') try: ev_sqrt_i = 1 / ev_sqrt ev_sqrt[zeros] = 0 ev_sqrt_i[zeros] = 0 finally: sp.seterr(divide=err['divide'], invalid=err['invalid']) if EV is None: x_sqrt = mm.simple_diag_matrix(ev_sqrt, dtype=x.dtype) x_sqrt_i = mm.simple_diag_matrix(ev_sqrt_i, dtype=x.dtype) else: B = mm.mmul_diag(ev_sqrt, EV.conj().T) x_sqrt = EV.dot(B) B = mm.mmul_diag(ev_sqrt_i, EV.conj().T) x_sqrt_i = EV.dot(B) rank = x.shape[0] - np.count_nonzero(zeros) if sanity_checks: if ev.min() < -zero_tol: log.warning("Sanity Fail in herm_sqrt_inv(): Throwing away negative eigenvalues! %s %s", ev.min(), sc_data) if not np.allclose(x_sqrt.dot(x_sqrt), x): log.warning("Sanity Fail in herm_sqrt_inv(): x_sqrt is bad! %s %s", la.norm(x_sqrt.dot(x_sqrt) - x), sc_data) if EV is None: nulls = sp.zeros(x.shape[0]) nulls[zeros] = 1 nulls = sp.diag(nulls) else: #if we did an EVD then we use the eigenvectors nulls = EV.copy() nulls[:, sp.invert(zeros)] = 0 nulls = nulls.dot(nulls.conj().T) eye = np.eye(x.shape[0]) if not np.allclose(x_sqrt.dot(x_sqrt_i), eye - nulls): log.warning("Sanity Fail in herm_sqrt_inv(): x_sqrt_i is bad! %s %s", la.norm(x_sqrt.dot(x_sqrt_i) - eye + nulls), sc_data) if return_rank: return x_sqrt, x_sqrt_i, rank else: return x_sqrt, x_sqrt_i
def restore_RCF_l(A, lm1, Gm1, sanity_checks=False): """Transforms a single A[n] to obtain diagonal l[n]. Applied after restore_RCF_r(), this completes the full canonical form of sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This function must be called for each n in turn, starting at 1, passing the gauge transformation matrix from the previous step as an argument. Finds a G[n] such that orthonormalization is fulfilled for n. The diagonal entries of l[n] are sorted in ascending order (for example l[n] = diag([0, 0, 0.1, 0.2, ...])). Parameters ---------- A : ndarray The parameter tensor for the nth site A[n]. lm1 : ndarray or object with array interface The matrix l[n - 1]. Gm1 : ndarray The gauge transform matrix for site n obtained in the previous step (for n - 1). sanity_checks : bool (False) Whether to perform additional sanity checks. Returns ------- l : ndarray or simple_diag_matrix The new, diagonal matrix l[n]. G : ndarray The gauge transformation matrix for site n. G_i : ndarray Inverse of G. """ if Gm1 is None: x = lm1 else: x = Gm1.conj().T.dot(lm1.dot(Gm1)) M = eps_l_noop(x, A, A) ev, EV = la.eigh(M) #wraps lapack routines, which return eigenvalues in ascending order if sanity_checks: assert np.all(ev == np.sort(ev)), "unexpected eigenvalue ordering" l = mm.simple_diag_matrix(ev, dtype=A.dtype) G_i = EV if Gm1 is None: Gm1 = EV.conj().T #for left uniform case lm1 = l #for sanity check for s in xrange(A.shape[0]): A[s] = Gm1.dot(A[s].dot(G_i)) if sanity_checks: l_ = eps_l_noop(lm1, A, A) if not sp.allclose(l_, l, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF_l!: l is bad!") log.warning(la.norm(l_ - l)) G = EV.conj().T return l, G, G_i
def restore_RCF(self, dbg=False): if dbg: self.calc_l() self.calc_r() print "BEFORE..." h_before, h_left_before, h_right_before = self.restore_RCF_dbg() print (h_left_before, h_before, h_right_before) self.restore_RCF_r() if dbg: self.calc_l() print "MIDDLE..." h_mid, h_left_mid, h_right_mid = self.restore_RCF_dbg() print (h_left_mid, h_mid, h_right_mid) fac = 1 / self.l[0].trace().real if dbg: print "Scale l[0]: %g" % fac self.l[0] *= fac self.u_gnd_l.r *= 1/fac self.restore_RCF_l() if dbg: print "Uni left:" self.u_gnd_l.A = self.A[0] self.u_gnd_l.l = self.l[0] self.u_gnd_l.calc_lr() #Ensures largest ev of E=1 self.l[0] = self.u_gnd_l.l #No longer diagonal! self.A[0] = self.u_gnd_l.A if self.sanity_checks: if not sp.allclose(self.l[0], sp.diag(sp.diag(self.l[0])), atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF!: True l[0] not diagonal!" self.l[0] = mm.simple_diag_matrix(sp.diag(self.l[0])) fac = 1 / sp.trace(self.l[0]).real if dbg: print "Scale l[0]: %g" % fac self.l[0] *= fac self.u_gnd_l.r *= 1/fac self.u_gnd_l.l = self.l[0] if dbg: print "Uni right:" self.u_gnd_r.A = self.A[self.N + 1] self.u_gnd_r.r = self.r[self.N] self.u_gnd_r.calc_lr() #Ensures largest ev of E=1 self.r[self.N] = self.u_gnd_r.r self.A[self.N + 1] = self.u_gnd_r.A if self.sanity_checks: if not sp.allclose(self.r[self.N], sp.eye(self.D[self.N]), atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF!: True r[N] not eye!" self.r[self.N] = mm.eyemat(self.D[self.N], dtype=self.typ) self.u_gnd_r.r = self.r[self.N] self.r[self.N + 1] = self.r[self.N] self.l[self.N + 1][:] = self.eps_l(self.N + 1, self.l[self.N]) if self.sanity_checks: l_n = self.l[0] for n in xrange(0, self.N + 1): l_n = self.eps_l(n, l_n) if not sp.allclose(l_n, self.l[n], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF!: l_%u is bad" % n r_nm1 = self.r[self.N + 1] for n in reversed(xrange(1, self.N + 2)): r_nm1 = self.eps_r(n, r_nm1) if not sp.allclose(r_nm1, self.r[n - 1], atol=1E-12, rtol=1E-12): print "Sanity Fail in restore_RCF!: r_%u is bad" % (n - 1) if dbg: print "AFTER..." h_after, h_left_after, h_right_after = self.restore_RCF_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, ret_g=False): if self.symm_gauge: self.restore_SCF() else: #First get G such that r = eye G = la.cholesky(self.r, lower=True) G_i = m.invtr(G, lower=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) if self.sanity_checks: M = np.zeros_like(self.r) for s in xrange(self.q): M += m.mmul(self.A[s], m.H(self.A[s])) self.r = m.mmul(G_i, self.r, m.H(G_i)) if not np.allclose(M, self.r, rtol=self.itr_rtol*self.check_fac, atol=self.itr_atol*self.check_fac): print "Sanity check failed: RestoreRCF, bad M." print "Off by: " + str(la.norm(M - self.r)) if not np.allclose(self.r, np.eye(self.D), rtol=self.itr_rtol*self.check_fac, atol=self.itr_atol*self.check_fac): print "Sanity check failed: r not identity." print "Off by: " + str(la.norm(np.eye(self.D) - self.r)) l = self.eps_l(self.l) r = self.eps_r(self.r) if not np.allclose(r, self.r, rtol=self.itr_rtol*self.check_fac, atol=self.itr_atol*self.check_fac): print "Sanity check failed: Restore_RCF, bad r!" print "Off by: " + str(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): print "Sanity check failed: Restore_RCF, bad l!" print "Off by: " + str(la.norm(l - self.l)) self.r = m.eyemat(self.D, dtype=self.typ) if ret_g: return G, G_i else: return
def restore_RCF_r(A, r, G_n_i, zero_tol=1E-15, sanity_checks=False, sc_data=''): """Transforms a single A[n] to obtain r[n - 1] = eye(D). Implements the condition for right-orthonormalization from sub-section 3.1, theorem 1 of arXiv:quant-ph/0608197v2. This function must be called for each n in turn, starting at N + 1, passing the gauge transformation matrix from the previous step as an argument. Finds a G[n-1] such that orthonormalization is fulfilled for n. If rank-deficiency is encountered, the result fulfills the orthonormality condition in the occupied subspace with the zeros at the top-left (for example r = diag([0, 0, 1, 1, 1, 1, 1])). Parameters ---------- A : ndarray The parameter tensor for the nth site A[n]. r : ndarray or object with array interface The matrix r[n]. G_n_i : ndarray The inverse gauge transform matrix for site n obtained in the previous step (for n + 1). sanity_checks : bool (False) Whether to perform additional sanity checks. zero_tol : float Tolerance for detecting zeros. Returns ------- r_nm1 : ndarray or simple_diag_matrix or eyemat The new matrix r[n - 1]. G_nm1 : ndarray The gauge transformation matrix for the site n - 1. G_n_m1_i : ndarray The inverse gauge transformation matrix for the site n - 1. """ if G_n_i is None: GGh_n_i = r else: GGh_n_i = G_n_i.dot(r.dot(G_n_i.conj().T)) M = eps_r_noop(GGh_n_i, A, A) X, Xi, new_D = herm_fac_with_inv(M, zero_tol=zero_tol, return_rank=True, sanity_checks=sanity_checks) G_nm1 = Xi.conj().T G_nm1_i = X.conj().T if G_n_i is None: G_n_i = G_nm1_i if sanity_checks: #GiG may not be equal to eye in the case of rank-deficiency, #but the rest should lie in the null space of A. GiG = G_nm1_i.dot(G_nm1) As = np.sum(A, axis=0) if not sp.allclose(GiG.dot(As).dot(G_n_i), As.dot(G_n_i), atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_RCF_r!: Bad GT! %s %s", la.norm(GiG.dot(As).dot(G_n_i) - As.dot(G_n_i)), sc_data) for s in xrange(A.shape[0]): A[s] = G_nm1.dot(A[s]).dot(G_n_i) if new_D == A.shape[1]: r_nm1 = mm.eyemat(A.shape[1], A.dtype) else: r_nm1 = sp.zeros((A.shape[1]), dtype=A.dtype) r_nm1[-new_D:] = 1 r_nm1 = mm.simple_diag_matrix(r_nm1, dtype=A.dtype) if sanity_checks: r_nm1_ = G_nm1.dot(M).dot(G_nm1.conj().T) if not sp.allclose(r_nm1_, r_nm1.A, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_RCF_r!: r != g old_r gH! %s %s", la.norm(r_nm1_ - r_nm1), sc_data) r_nm1_ = eps_r_noop(r, A, A) if not sp.allclose(r_nm1_, r_nm1.A, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_RCF_r!: r is bad! %s %s", la.norm(r_nm1_ - r_nm1), sc_data) return r_nm1, G_nm1, G_nm1_i