def setUp(self): #TODO: Test rectangular x as well self.d = [2, 3] self.D = [2, 4, 3] self.l0 = sp.rand(self.D[0], self.D[0]) + 1.j * sp.rand(self.D[0], self.D[0]) self.r1 = sp.rand(self.D[1], self.D[1]) + 1.j * sp.rand(self.D[1], self.D[1]) self.r2 = sp.rand(self.D[2], self.D[2]) + 1.j * sp.rand(self.D[2], self.D[2]) self.ld0 = mm.simple_diag_matrix( sp.rand(self.D[0]) + 1.j * sp.rand(self.D[0])) self.rd1 = mm.simple_diag_matrix( sp.rand(self.D[1]) + 1.j * sp.rand(self.D[1])) self.rd2 = mm.simple_diag_matrix( sp.rand(self.D[2]) + 1.j * sp.rand(self.D[2])) self.eye0 = mm.eyemat(self.D[0], dtype=sp.complex128) self.eye1 = mm.eyemat(self.D[1], dtype=sp.complex128) self.eye2 = mm.eyemat(self.D[2], dtype=sp.complex128) self.A0 = sp.rand(self.d[0], self.D[0], self.D[0]) + 1.j * sp.rand( self.d[0], self.D[0], self.D[0]) self.A1 = sp.rand(self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand( self.d[0], self.D[0], self.D[1]) self.A2 = sp.rand(self.d[1], self.D[1], self.D[2]) + 1.j * sp.rand( self.d[1], self.D[1], self.D[2]) self.A3 = sp.rand(self.d[1], self.D[2], self.D[2]) + 1.j * sp.rand( self.d[1], self.D[2], self.D[2]) self.B1 = sp.rand(self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand( self.d[0], self.D[0], self.D[1]) self.B2 = sp.rand(self.d[1], self.D[1], self.D[2]) + 1.j * sp.rand( self.d[1], self.D[1], self.D[2]) self.E1_AB = make_E_noop(self.A1, self.B1) self.E2_AB = make_E_noop(self.A2, self.B2) self.op1s_1 = sp.rand(self.d[0], self.d[0]) + 1.j * sp.rand(self.d[0], self.d[0]) self.E1_op_AB = make_E_1s(self.A1, self.B1, self.op1s_1) self.op2s = sp.rand(self.d[0], self.d[1], self.d[0], self.d[1]) + 1.j * sp.rand( self.d[0], self.d[1], self.d[0], self.d[1]) self.E12_op = make_E_2s(self.A1, self.A2, self.B1, self.B2, self.op2s) self.AA12 = tc.calc_AA(self.A1, self.A2) self.BB12 = tc.calc_AA(self.B1, self.B2) self.C_A12 = tc.calc_C_mat_op_AA(self.op2s, self.AA12) self.C_conj_B12 = tc.calc_C_conj_mat_op_AA(self.op2s, self.BB12) self.C01 = sp.rand(self.d[0], self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand( self.d[0], self.d[0], self.D[0], self.D[1])
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 setUp(self): #TODO: Test rectangular x as well self.d = [2, 3] self.D = [2, 4, 3] self.l0 = sp.rand(self.D[0], self.D[0]) + 1.j * sp.rand(self.D[0], self.D[0]) self.r1 = sp.rand(self.D[1], self.D[1]) + 1.j * sp.rand(self.D[1], self.D[1]) self.r2 = sp.rand(self.D[2], self.D[2]) + 1.j * sp.rand(self.D[2], self.D[2]) self.ld0 = mm.simple_diag_matrix(sp.rand(self.D[0]) + 1.j * sp.rand(self.D[0])) self.rd1 = mm.simple_diag_matrix(sp.rand(self.D[1]) + 1.j * sp.rand(self.D[1])) self.rd2 = mm.simple_diag_matrix(sp.rand(self.D[2]) + 1.j * sp.rand(self.D[2])) self.eye0 = mm.eyemat(self.D[0], dtype=sp.complex128) self.eye1 = mm.eyemat(self.D[1], dtype=sp.complex128) self.eye2 = mm.eyemat(self.D[2], dtype=sp.complex128) self.A0 = sp.rand(self.d[0], self.D[0], self.D[0]) + 1.j * sp.rand(self.d[0], self.D[0], self.D[0]) self.A1 = sp.rand(self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand(self.d[0], self.D[0], self.D[1]) self.A2 = sp.rand(self.d[1], self.D[1], self.D[2]) + 1.j * sp.rand(self.d[1], self.D[1], self.D[2]) self.A3 = sp.rand(self.d[1], self.D[2], self.D[2]) + 1.j * sp.rand(self.d[1], self.D[2], self.D[2]) self.B1 = sp.rand(self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand(self.d[0], self.D[0], self.D[1]) self.B2 = sp.rand(self.d[1], self.D[1], self.D[2]) + 1.j * sp.rand(self.d[1], self.D[1], self.D[2]) self.E1_AB = make_E_noop(self.A1, self.B1) self.E2_AB = make_E_noop(self.A2, self.B2) self.op1s_1 = sp.rand(self.d[0], self.d[0]) + 1.j * sp.rand(self.d[0], self.d[0]) self.E1_op_AB = make_E_1s(self.A1, self.B1, self.op1s_1) self.op2s = sp.rand(self.d[0], self.d[1], self.d[0], self.d[1]) + 1.j * sp.rand(self.d[0], self.d[1], self.d[0], self.d[1]) self.E12_op = make_E_2s(self.A1, self.A2, self.B1, self.B2, self.op2s) self.AA12 = tc.calc_AA(self.A1, self.A2) self.BB12 = tc.calc_AA(self.B1, self.B2) self.C_A12 = tc.calc_C_mat_op_AA(self.op2s, self.AA12) self.C_conj_B12 = tc.calc_C_conj_mat_op_AA(self.op2s, self.BB12) self.C01 = sp.rand(self.d[0], self.d[0], self.D[0], self.D[1]) + 1.j * sp.rand(self.d[0], self.d[0], self.D[0], self.D[1])
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 if sanity_checks: eye = sp.eye(A.shape[1]) if not sp.allclose(sp.dot(Gm1, Gm1_i), eye, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF_r!: Bad GT! (off by %g)", la.norm(sp.dot(Gm1, Gm1_i) - eye)) 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 if sanity_checks: eye = sp.eye(A.shape[1]) if not sp.allclose(sp.dot(Gm1, Gm1_i), eye, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_LCF_r!: Bad GT! (off by %g)", la.norm(sp.dot(Gm1, Gm1_i) - eye)) return rm1, Gm1, Gm1_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, 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. 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) xi = mm.invtr(x, lower=lower) 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:]) #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) ev_sq = mm.simple_diag_matrix(ev_sq, dtype=A.dtype) if lower: x = ev_sq.dot_left(EV) xi = ev_sq_i.dot(EV.conj().T) else: x = ev_sq.dot(EV.conj().T) 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 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(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) 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) else: 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(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 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 return_rank: return x, xi, nonzeros else: return x, xi
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 if sanity_checks: eye = sp.eye(A.shape[2]) if not sp.allclose(sp.dot(G, G_i), eye, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF_l!: Bad GT! (off by %g)", la.norm(sp.dot(G, G_i) - eye)) 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, 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. 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) xi = mm.invtr(x, lower=lower) 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:]) #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) ev_sq = mm.simple_diag_matrix(ev_sq, dtype=A.dtype) if lower: x = ev_sq.dot_left(EV) xi = ev_sq_i.dot(EV.conj().T) else: x = ev_sq.dot(EV.conj().T) 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 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(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) 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) else: 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(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 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 return_rank: return x, xi, nonzeros else: return x, xi
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 if sanity_checks: eye = sp.eye(A.shape[2]) if not sp.allclose(sp.dot(G, G_i), eye, atol=1E-12, rtol=1E-12): log.warning("Sanity Fail in restore_RCF_l!: Bad GT! (off by %g)", la.norm(sp.dot(G, G_i) - eye)) return l, G, G_i