torch
fdpyutils.torch.kronecker.best_kronecker
best_kronecker(A: Tensor, B_shape: Tuple[int, int], C_shape: Tuple[int, int], svd_backend: str = 'torch') -> Tuple[Tensor, Tensor, Tensor]
Find the best approximation \(\alpha (B \otimes C)\) of \(A\).
'Best' means in terms of Frobenius norm. Requires computing the top singular vectors of a reshape of \(A\). See this paper for details.
Parameters:
-
A(Tensor) –The matrix to approximate.
-
B_shape(Tuple[int, int]) –The shape of the first tensor in the Kronecker product.
-
C_shape(Tuple[int, int]) –The shape of the second tensor in the Kronecker product.
-
svd_backend(str, default:'torch') –The backend to use for SVD. Defaults to 'torch', which computes a full SVD. The alternative choice is 'scipy', which loads the matrix to CPU and uses SciPy's truncated SVD
scipy.sparse.linalg.svdsthat may require fewer matrix-vector products.
Returns:
-
Tuple[Tensor, Tensor, Tensor]–The scalar \(\alpha\) and the matrices \(B, C\) such that \(\alpha (B \otimes C)\) is the best Kronecker approximation of \(A\).
Raises:
-
ValueError–If A is not a matrix.
-
ValueError–If
B_shapeorC_shapeare not 2-tuples. -
ValueError–If the shapes multiply to the incorrect total dimension.
-
ValueError–If the value of
svd_backendis unsupported.
Examples:
>>> from torch import kron, rand, manual_seed
>>> _ = manual_seed(0) # make deterministic
>>> # generate a random Kronecker product
>>> shape_B, shape_C = (2, 3), (4, 5)
>>> A = kron(rand(*shape_B), rand(*shape_C))
>>> # find the best Kronecker approximation and check reconstruction matches
>>> alpha, B, C = best_kronecker(A, shape_B, shape_C)
>>> A.allclose(alpha * kron(B, C))
True