I understand how to perform SVD reconstruction for the 2D case,
import numpy as np
a = np.random.rand(20, 20)
u, s, vh = np.linalg.svd(a)
b = u * s @ vh
assert np.allclose(a, b)
But I do not understand how to perform SVD reconstruction for the 3D case (specifically for a (k,k,n) matrix, where n is the third dimension)
ValueError Traceback (most recent call last)
<ipython-input-131-40a909c464ae> in <module>
2 a = np.random.rand(20, 20, 40)
3 u, s, vh = np.linalg.svd(a)
----> 4 b = u * s @ vh
5 assert np.allclose(a, b)
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 40 is different from 20)
Unfortunately, the document https://numpy.org/doc/stable/reference/generated/numpy.linalg.svd.html only has examples for the 2D and 4D cases. How would I perform the reconstruction in a 3D case?
CodePudding user response:
First, try a non-square matrix:
s
will have the smallest of the two dimensions as size (the other entries would be always zero). We can slice the other matrices, removing the parts that would be multiplied by zero getting this
np
a = np.random.rand(20, 30)
u, s, vh = np.linalg.svd(a)
b = (u[:,:len(s)] * s) @ vh[:len(s),:]
The SVD for multiple dimensions will simply apply the 2D SVD for each matrix using the two last dimensions. The outputs will have the same N-2 dimensions as the inputs, and the other will be the same as if SVD was applied to a single matrix. So we can write a reconstruction as follows
a = np.random.rand(20, 30, 40)
u, s, vh = np.linalg.svd(a)
b = (u[...,:,:s.shape[-1]] * s[...,None,:]) @ vh[..., :s.shape[-1],:]
assert np.allclose(a, b)
(this will run 20 SVDs on matrices of dimension 30 x 40)