up_svd_pair#
- t3toolbox.backend.linalg.up_svd_pair(G_i_a_j, B_a_o, min_rank=None, max_rank=None, rtol=None, atol=None)#
def up_svd_pair( G_i_a_j: NDArray, # shape=(..., ni, na, nj) B_a_o: NDArray, # shape=(..., na, N) min_rank: int = None, # 1 <= min_rank <= max_rank <= minimum(ni*na, nj) max_rank: int = None, # 1 <= min_rank <= max_rank <= minimum(ni*na, nj) rtol: float = None, # removes singular values satisfying sigma < maximum(atol, rtol*sigma1) atol: float = None, # removes singular values satisfying sigma < maximum(atol, rtol*sigma1) ) -> typ.Tuple[ NDArray, # new_G, shape=(..., ni, nx, nj), NDArray, # new_B, shape=(..., nx, N) NDArray, # ss, shape=(..., nx) ]:
Compute (truncated) singular value decomposition of G, pushing non-orthogonal remainder onto B.
G(a 3-tensor core) andB(a matrix) shareG’s middle index withB’s first index. OrthogonalizesGvia its up unfolding (sonew_Gis up-orthonormal) and absorbs thess @ Vtremainder intoB, leaving the product over the shared index unchanged. Truncation args behave as intruncated_svd().Examples
>>> import numpy as np >>> import t3toolbox.backend.linalg as linalg >>> np.random.seed(0) >>> G = np.random.randn(2, 3, 4) # (ni, na, nj) >>> B = np.random.randn(3, 7) # (na, N) -- shared index na=3 >>> new_G, new_B, ss = linalg.up_svd_pair(G, B) >>> print(new_G.shape, new_B.shape, ss.shape) (2, 3, 4) (3, 7) (3,) >>> before = np.einsum('iaj,ao->ijo', G, B) >>> after = np.einsum('ixj,xo->ijo', new_G, new_B) >>> print(np.allclose(before, after)) # product across the shared index preserved True >>> Um = new_G.transpose(0, 2, 1).reshape(2 * 4, -1) >>> print(np.allclose(Um.T @ Um, np.eye(Um.shape[1]))) # new_G is up-orthonormal True