def calc_x_tp(Kp1, C_tp, Cm1_tp, rp1, lm2, Am1, A, Ap1, lm1_s, lm1_si, r_s, r_si, Vsh): D = A.shape[2] Dm1 = A.shape[1] q = A.shape[0] x = np.zeros((Dm1, q * D - Dm1), dtype=A.dtype) V = sp.transpose(Vsh, axes=(0, 2, 1)).conj().copy() Vri = V.copy() try: for Vris in Vri: Vris[:] = r_si.dot_left(Vris) except AttributeError: for Vris in Vri: Vris[:] = Vris.dot(r_si) if not C_tp is None: x += lm1_s.dot(eps_r_op_2s_C12_tp(rp1, C_tp, Vri, Ap1)) #1 if not Cm1_tp is None: for al in xrange(len(Cm1_tp)): x += lm1_si.dot(eps_l_noop(lm2, Am1, Cm1_tp[al][0]).dot(eps_r_noop(r_s, Cm1_tp[al][1], V))) #2 if not Kp1 is None: x += lm1_s.dot(eps_r_noop(Kp1, A, Vri)) return x
def calc_Vsh_l(A, lm1_sqrt, sanity_checks=False): D = A.shape[2] Dm1 = A.shape[1] q = A.shape[0] if q * Dm1 - D <= 0: return None L = sp.zeros((D, q, Dm1), dtype=A.dtype, order='C') for s in xrange(q): L[:, s, :] = lm1_sqrt.dot(A[s]).conj().T L = L.reshape((D, q * Dm1)) V = ns.nullspace_qr(L) if sanity_checks: if not sp.allclose(L.dot(V), 0): log.warning("Sanity Fail in calc_Vsh_l!: LV != 0") if not sp.allclose(V.conj().T.dot(V), sp.eye(V.shape[1])): log.warning("Sanity Fail in calc_Vsh_l!: V H(V) != eye") V = V.reshape((q, Dm1, q * Dm1 - D)) Vsh = sp.transpose(V.conj(), axes=(0, 2, 1)) Vsh = sp.asarray(Vsh, order='C') if sanity_checks: M = eps_l_noop(lm1_sqrt, A, V) if not sp.allclose(M, 0): log.warning("Sanity Fail in calc_Vsh_l!: Bad Vsh") return Vsh
def calc_x_tp(Kp1, C_tp, Cm1_tp, rp1, lm2, Am1, A, Ap1, lm1_s, lm1_si, r_s, r_si, Vsh): D = A.shape[2] Dm1 = A.shape[1] q = A.shape[0] x = np.zeros((Dm1, q * D - Dm1), dtype=A.dtype) V = sp.transpose(Vsh, axes=(0, 2, 1)).conj().copy() Vri = V.copy() try: for Vris in Vri: Vris[:] = r_si.dot_left(Vris) except AttributeError: for Vris in Vri: Vris[:] = Vris.dot(r_si) if not C_tp is None: x += lm1_s.dot(eps_r_op_2s_C12_tp(rp1, C_tp, Vri, Ap1)) #1 if not Cm1_tp is None: for al in xrange(len(Cm1_tp)): x += lm1_si.dot( eps_l_noop(lm2, Am1, Cm1_tp[al][0]).dot( eps_r_noop(r_s, Cm1_tp[al][1], V))) #2 if not Kp1 is None: x += lm1_s.dot(eps_r_noop(Kp1, A, Vri)) return x
def calc_Vsh_l(A, lm1_sqrt, sanity_checks=False): D = A.shape[2] Dm1 = A.shape[1] q = A.shape[0] if q * Dm1 - D <= 0: return None L = sp.zeros((D, q, Dm1), dtype=A.dtype, order='C') for s in xrange(q): L[:,s,:] = lm1_sqrt.dot(A[s]).conj().T L = L.reshape((D, q * Dm1)) V = ns.nullspace_qr(L) if sanity_checks: if not sp.allclose(L.dot(V), 0): log.warning("Sanity Fail in calc_Vsh_l!: LV != 0") if not sp.allclose(V.conj().T.dot(V), sp.eye(V.shape[1])): log.warning("Sanity Fail in calc_Vsh_l!: V H(V) != eye") V = V.reshape((q, Dm1, q * Dm1 - D)) Vsh = sp.transpose(V.conj(), axes=(0, 2, 1)) Vsh = sp.asarray(Vsh, order='C') if sanity_checks: M = eps_l_noop(lm1_sqrt, A, V) if not sp.allclose(M, 0): log.warning("Sanity Fail in calc_Vsh_l!: Bad Vsh") return Vsh
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 calc_K_3s_l(Km1, Cm2, lm3, r, A, Am2Am1A): K = eps_l_noop(Km1, A, A) Hl = eps_l_op_3s_AAA123_C456(lm3, Am2Am1A, Cm2) op_expect = mm.adot_noconj(Hl, r) K += Hl return K, op_expect
def calc_K_l_tp(Km1, lm2, r, Am1, A, Cm1_tp): K = eps_l_noop(Km1, A, A) Hl = eps_l_op_2s_C34_tp(lm2, Am1, A, Cm1_tp) op_expect = mm.adot_noconj(Hl, r) K += Hl return K, op_expect
def calc_BB_Y_2s_tp(C_tp, Vlh, Vrh_p1, l_s_m1, r_s_p1): Vl = sp.transpose(Vlh, axes=(0, 2, 1)).conj().copy() Vr_p1 = sp.transpose(Vrh_p1, axes=(0, 2, 1)).conj().copy() Y = 0 for al in xrange(len(C_tp)): Y += eps_l_noop(l_s_m1, Vl, C_tp[al][0]).dot(eps_r_noop(r_s_p1, C_tp[al][1], Vr_p1)) etaBB_sq = mm.adot(Y, Y) return Y, etaBB_sq
def calc_BB_Y_2s_tp(C_tp, Vlh, Vrh_p1, l_s_m1, r_s_p1): Vl = sp.transpose(Vlh, axes=(0, 2, 1)).conj().copy() Vr_p1 = sp.transpose(Vrh_p1, axes=(0, 2, 1)).conj().copy() Y = 0 for al in range(len(C_tp)): Y += eps_l_noop(l_s_m1, Vl, C_tp[al][0]).dot(eps_r_noop(r_s_p1, C_tp[al][1], Vr_p1)) etaBB_sq = mm.adot(Y, Y) return Y, etaBB_sq
def calc_K_l(Km1, Cm1, lm2, r, A, Am1A): """Calculates the K_left using the recursive definition. This is the "bra-vector" K_left, which means (K_left.dot(r)).trace() = <K_left|r>. In other words, K_left ~ <K_left| and K_left.conj().T ~ |K_left>. """ K = eps_l_noop(Km1, A, A) Hl = eps_l_op_2s_AA12_C34(lm2, Am1A, Cm1) op_expect = mm.adot_noconj(Hl, r) K += Hl return K, op_expect
def restore_LCF_l_seq(A, l, G0=None, sanity_checks=False, sc_data=''): """Transforms a sequence of A[n]'s to obtain l[n] = eye(D). Implements the condition for left-orthonormalization. Uses a reduced QR (RQ) decomposition to avoid inverting anything explicity. Parameters ---------- A : sequence of ndarray The parameter tensors for a sequence of sites [None, A1, A2,..., AN]. The first entry is ignored so that the indices match up with l. l : sequence of ndarray or objects with array interface The matrices [l0, l1, l2,..., lN], where l0 will not be changed, but is used for sanity checks. G0 : ndarray or scalar Initial left gauge transformation matrix for site 0. Only needed when used as part of a larger transformation. sanity_checks : bool (False) Whether to perform additional sanity checks. sc_data : string A string to be appended to sanity check log messages. """ if G0 is None: G = mm.eyemat(A[1].shape[1], dtype=A[1].dtype) else: G = G0 for n in xrange(1, len(A)): q, Dm1, D = A[n].shape GA = sp.array([G.dot(As) for As in A[n]]) GA = GA.reshape((q * Dm1, D)) Q, G = la.qr(GA, mode='economic') A[n] = Q.reshape((q, Dm1, D)) l[n] = mm.eyemat(D, dtype=A[n].dtype) if sanity_checks: l_ = eps_l_noop(l[n - 1], A[n], A[n]) if not sp.allclose(l_, l[n].A, atol=1E-13, rtol=1E-13): log.warning("Sanity Fail in restore_LCF_l_seq!: l is bad") log.warning(la.norm(l_ - l[n].A)) return G
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 eps_l_op_2s_AA12_C34(x, AA12, C34): d = AA12.shape[0] * AA12.shape[1] S1 = (d, AA12.shape[2], AA12.shape[3]) S2 = (d, C34.shape[2], C34.shape[3]) return eps_l_noop(x, AA12.reshape(S1), C34.reshape(S2))
def eps_l_op_3s_AAA123_C456(x, AAA123, C456): d = C456.shape[0] * C456.shape[1] * C456.shape[2] S1 = (d, AAA123.shape[3], AAA123.shape[4]) S2 = (d, C456.shape[3], C456.shape[4]) return eps_l_noop(x, AAA123.reshape(S1), C456.reshape(S2))
def eps_l_op_2s_C34_tp(x, A1, A2, C34_tp): res = 0 for al in xrange(len(C34_tp)): res += eps_l_noop(eps_l_noop(x, A1, C34_tp[al][0]), A2, C34_tp[al][1]) return res
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