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 restore_ONR_n(self, n, G_n_i): """Transforms a single A[n] to obtain right orthonormalization. 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 ON_R is fulfilled for n. Eigenvalues = 0 are a problem here... IOW rank-deficient matrices. Apparently, they can turn up during a run, but if they do we're screwed. The fact that M should be positive definite is used to optimize this. Parameters ---------- n : int The site number. G_n_i : ndarray The inverse gauge transform matrix for site n obtained in the previous step (for n + 1). Returns ------- G_n_m1_i : ndarray The inverse gauge transformation matrix for the site n - 1. """ if G_n_i is None: GGh_n_i = self.r[n] else: GGh_n_i = mm.mmul(G_n_i, self.r[n], mm.H(G_n_i)) M = self.eps_r(n, GGh_n_i) try: tu = la.cholesky(M) #Assumes M is pos. def.. It should raise LinAlgError if not. G_nm1 = mm.H(mm.invtr(tu)) #G is now lower-triangular G_nm1_i = mm.H(tu) except sp.linalg.LinAlgError: print "Restore_ON_R_%u: Falling back to eigh()!" % n e,Gh = la.eigh(M) G_nm1 = mm.H(mm.mmul(Gh, sp.diag(1/sp.sqrt(e) + 0.j))) G_nm1_i = la.inv(G_nm1) if G_n_i is None: G_n_i = G_nm1_i if self.sanity_checks: if not sp.allclose(sp.dot(G_nm1, G_nm1_i), sp.eye(G_nm1.shape[0]), atol=1E-13, rtol=1E-13): print "Sanity Fail in restore_ONR_%u!: Bad GT at n=%u" % (n, n) for s in xrange(self.q[n]): self.A[n][s] = mm.mmul(G_nm1, self.A[n][s], G_n_i) return G_nm1_i, G_nm1
def restore_ONR_n(self, n, G_n_i): """Transforms a single A[n] to obtain right orthonormalization. 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 ON_R is fulfilled for n. Eigenvalues = 0 are a problem here... IOW rank-deficient matrices. Apparently, they can turn up during a run, but if they do we're screwed. The fact that M should be positive definite is used to optimize this. Parameters ---------- n : int The site number. G_n_i : ndarray The inverse gauge transform matrix for site n obtained in the previous step (for n + 1). Returns ------- G_n_m1_i : ndarray The inverse gauge transformation matrix for the site n - 1. """ GGh_n_i = m.mmul( G_n_i, m.H(G_n_i) ) #r[n] does not belong here. The condition is for sum(AA). r[n] = 1 is a consequence. M = self.eps_r(n, GGh_n_i) #The following should be more efficient than eigh(): try: tu = la.cholesky( M ) #Assumes M is pos. def.. It should raise LinAlgError if not. G_nm1 = m.H(m.invtr(tu)) #G is now lower-triangular G_nm1_i = m.H(tu) except sp.linalg.LinAlgError: print "restore_ONR_n: Falling back to eigh()!" e, Gh = la.eigh(M) G_nm1 = m.H(m.mmul(Gh, sp.diag(1 / sp.sqrt(e) + 0.j))) G_nm1_i = la.inv(G_nm1) for s in xrange(self.q[n]): self.A[n][s] = m.mmul(G_nm1, self.A[n][s], G_n_i) #It's ok to use the same matrix as out and as an operand here #since there are > 2 matrices in the chain and it is not the last argument. return G_nm1_i
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 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 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