dask: svd_compressed() fails for complex input
What happened:
Complex singular values and vectors of svd_compressed() are different from standard np.linalg.svd.
What you expected to happen:
Complex singular values and vectors of svd_compressed() are similar (within some uncertainties) to standard np.linalg.svd.
Minimal Complete Verifiable Example:
import numpy as np
import xarray as xr
import dask.array as da
from matplotlib.pyplot import imshow
data = xr.tutorial.open_dataset(
'air_temperature',
chunks={'lat': 25, 'lon': 25, 'time': -1}
)
temp = data.air
temp = temp.stack(x=('lat', 'lon')).compute()
temp -= temp.mean('time')
# artificial complexification of data
temp = temp + (1j * 0.1 * temp**2)
kernel = np.dot(temp.conj().T, temp) / temp.shape[0]
# standard SVD
u, s, vt = np.linalg.svd(kernel, full_matrices=False)
# dask SVD
dask_kernel = da.from_array(kernel)
k = 100
dsvd = da.linalg.svd_compressed(dask_kernel, k)
u2, s2, vt2 = (x.compute() for x in dsvd)
np.allclose(s[:100], s2) # False
np.allclose(vt[:100], vt2) # False
# visual check: look at first singular vector
v = vt.reshape((temp.shape[1],) + data.air.shape[1:])
v2 = vt2.reshape((k,) + data.air.shape[1:])
# imaginary parts of first singular vector are clearly different
imshow(v[0,:,:].imag, vmin=-1e-3, vmax=1e-3)
imshow(-v2[0,:,:].imag, vmin=-1e-3, vmax=1e-3)
Anything else we need to know?:
- For real input, both methods yield the same results.
- When running
svd_compressed()a warning is thrown complaining about complex being casted to real dtypes:
/home/nrieger/anaconda3/envs/xmca/lib/python3.7/site-packages/dask/array/utils.py:108: ComplexWarning: Casting complex values to real discards the imaginary part
meta = meta.astype(dtype)
Environment:
- Dask version: 2021.04.0
- Python version: 3.7.10
- Operating System: Ubuntu 20.04
- Install method: conda
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 17 (12 by maintainers)
I think I have found the bugs in svd_compressed(). The svd calculation for complex matrix is $A=U\Sigma V^\dagger$, where $U$ and $V^\dagger$ are complex matrices. The " ${}^\dagger$ " means “Hermitian transpose”, which on the case of real matrix reduces to a transpose matrix. While calculating complex matrix svd, we should use Hermitian transpose but not transpose matrix. At the source code for dask.array.linalg, I found some bugs, and I will figure out the bugs by comments. First, at the “compression_matrix()” function,
Then, at the “svd_compressed()” function,
Here is my code of randomized svd by the use of power iteration
randomized_svd.py
Here is the test code, which compares to the full svd “cupy.linalg.svd” and “dask.array.linalg.svd_compressed”
test.py
The results are:
full svd by using cupy.linalg.svd()
ramdomized svd by using my function "rsvd()"
ramdomized svd by using dask.array.linalg.svd_compressed()
I calculated the trace and error of matrix $M-M'$, in which $M$ is the original matrix, and $$M_{ik} \simeq M^\prime_{ik}=\sum_{k=1}^{32} U_{ij} \sigma_{j} V^\dagger_{jk}.$$ The error is defined by $\text{err}=||M-M^\prime||/||M||$. The results show that my code yields a reasonable answer because the trace and error are quite small, and the large singular values are the same as full svd. By the way, the skinny matrix svd and tsqr seem to be currect because I used them in my code. But I’m not sure if there are the same bugs (at where should use Hermitian transpose, but have used tranpose matrix for complex matrix) in the code.
Just checked, the TSQR gives same results for complex matrices as numpy QR. I am not sure whether the sampling for complex matrices should also be a complex matrix.
@eric-czech: The SVD is unique (up to signs) for square, non-square, and complex matrices as long as no singular value pairs (two or more singular values with the same value exist). See Trefethen, L. N. & Bau III, D. Numerical linear algebra, vol. 50 (Siam, 1997).
I am not sure whether randomized methods such as svd_compressed provide unique solutions, as they severely depend on the sampling of the matrix. In my experience they are not unique.