def test_gauge_match_minimizes(backend, dtype, chi, d): """ Gauge matching decreases the values of ||A_C - A_L C || and ||A_C - C A_R||. """ A_L, C, A_R, _ = random_hermitian_system(backend, dtype, chi, d) A_C = tn.randn((chi, d, chi), dtype=dtype, backend=backend) epsL = tn.linalg.linalg.norm(A_C - ct.rightmult(A_L, C)) epsR = tn.linalg.linalg.norm(A_C - ct.leftmult(C, A_R)) A_L2, A_R2 = vumps.gauge_match(A_C, C, True) epsL2 = tn.linalg.linalg.norm(A_C - ct.rightmult(A_L2, C)) epsR2 = tn.linalg.linalg.norm(A_C - ct.leftmult(C, A_R2)) assert epsL2 < epsL assert epsR2 < epsR
def test_rightmult(backend, dtype, chi, d): lam = tn.randn((chi, chi), dtype=dtype, backend=backend, seed=10) gam = tn.randn((chi, d, chi), dtype=dtype, backend=backend, seed=10) result = ct.rightmult(gam, lam) compare = tn.linalg.operations.ncon([gam, lam], [[-1, -2, 1], [1, -3]]) np.testing.assert_allclose(result.array, compare.array)
def vumps_initialization( d: int, chi: int, dtype: Optional[DtypeType] = None, backend: Optional[Text] = None ) -> Tuple[ThreeTensors, tn.Tensor, TwoTensors]: """ Generate a random uMPS in mixed canonical forms, along with the left dominant eV L of A_L and right dominant eV R of A_R. Args: d: Physical dimension. chi: Bond dimension. dtype: Data dtype of tensors. backend: The backend. Returns: mps = (A_L, C, A_R): A_L and A_R have shape (chi, d, chi), and are respectively left and right isometric. C is the (chi, chi) centre of orthogonality. A_C: A_L @ C. One of the equations vumps minimizes is A_L @ C = C @ A_R = A_C. fpoints = [rL, lR]: C^dag @ C and C @ C^dag respectively. Will converge to the left and right fixed points of A_R and A_L. Both are chi x chi. """ A_1 = tn.randn((chi, d, chi), dtype=dtype, backend=backend) A_L, _ = tn.linalg.linalg.qr(A_1, pivot_axis=2, non_negative_diagonal=True) C, A_R = tn.linalg.linalg.rq(A_L, pivot_axis=1, non_negative_diagonal=True) C /= tn.linalg.linalg.norm(C) A_C = ct.rightmult(A_L, C) L0, R0 = vumps_approximate_tm_eigs(C) fpoints = (L0, R0) mps = [A_L, C, A_R] benchmark.block_until_ready(R0) return (mps, A_C, fpoints)
def vumps_delta(mps: ThreeTensors, A_C: tn.Tensor, oldA_L: tn.Tensor, mode: Text): """ Estimate the current vuMPS error. Args: mps: The MPS. A_C: Current A_C. oldA_L: A_L from the last iteration. mode: gradient_estimate_mode in vumps_params. See that docstring for details. """ if mode == "gauge mismatch": A_L, C, A_R = mps eL = tn.norm(A_C - ct.rightmult(A_L, C)) eR = tn.norm(A_C - ct.leftmult(C, A_R)) delta = max(eL, eR) elif mode == "null space": A_Ldag = tn.pivot(oldA_L, pivot_axis=2).H N_Ldag = tn_vumps.polar.null_space(A_Ldag) N_L = N_Ldag.H A_Cmat = tn.pivot(A_C, pivot_axis=2) B = N_L @ A_Cmat delta = tn.norm(B) else: raise ValueError("Invalid mode {mode}.") return delta
def gauge_match(A_C: tn.Tensor, C: tn.Tensor, mode: Text = "svd") -> TwoTensors: """ Return approximately gauge-matched A_L and A_R from A_C and C using a polar decomposition. A_L and A_R are chosen to minimize ||A_C - A_L C|| and ||A_C - C A_R||. The respective solutions are the isometric factors in the polar decompositions of A_C @ C.H and C.H @ A_C. Args: A_C: Current estimate of A_C. C: C from the MPS. mode: Chooses the algorithm for the polar decomposition. See the docstring of vumps_params in params.py. Returns: A_L, A_R: Such that A_L C A_R minimizes ||A_C - A_L C|| and ||A_C - C A_R||, with A_L (A_R) left (right) isometric. """ UC = tn_vumps.polar.polarU(C, mode=mode) # unitary UAc_l = tn_vumps.polar.polarU(A_C, mode=mode) # left isometric A_L = ct.rightmult(UAc_l, UC.H) UAc_r = tn_vumps.polar.polarU(A_C, pivot_axis=1, mode=mode) # right iso A_R = ct.leftmult(UC.H, UAc_r) return A_L, A_R
def test_gauge_match_left(backend, dtype, chi, d): """ Gauge matching is a null op on a system gauge matched on the LHS. """ A_L, C, _, _ = random_hermitian_system(backend, dtype, chi, d) A_C = ct.rightmult(A_L, C) A_L2, _ = vumps.gauge_match(A_C, C, True) rtol = 2 * A_L.size * C.size * A_C.size * np.finfo(dtype).eps np.testing.assert_allclose(A_L.array, A_L2.array, rtol=rtol) I = tn.eye(chi, backend=backend, dtype=dtype) XAL2 = ct.XopL(A_L2, I) np.testing.assert_allclose(XAL2.array, I.array, atol=rtol)