svdlibrs 
A Rust port of LAS2 from SVDLIBC
A library that computes an svd on a sparse matrix, typically a large sparse matrix
This is a functional port (mostly a translation) of the algorithm as implemented in Doug Rohde's SVDLIBC
This library performs singular value decomposition on a sparse input Matrix using the Lanczos algorithm and returns the decomposition as ndarray components.
Usage
Input: Sparse Matrix (CSR, CSC, or COO)
Output: decomposition U,S,V where U,V are Array2 and S is Array1, packaged in a Result<SvdRec, SvdLibError>
Quick Start
There are 3 convenience methods to handle common use cases
-
svd-- simply computes an SVD -
svd_dim-- computes an SVD supplying a desired numer ofdimensions -
svd_dim_seed-- computes an SVD supplying a desired numer ofdimensionsand a fixedseedto the LAS2 algorithm (the algorithm initializes with a random vector and will generate an internal seed if one isn't supplied)
use svd;
// SVD on a Compressed Sparse Row matrix
let svd = svd?;
use svd_dim;
// SVD on a Compressed Sparse Column matrix specifying the desired dimensions, 3 in this example
let svd = svd_dim?;
use svd_dim_seed;
// SVD on a Coordinate-form matrix requesting the
// dimensions and supplying a fixed seed to the LAS2 algorithm
let svd = svd_dim_seed?;
The SVD and informational Diagnostics are returned in SvdRec
The method svdLAS2 provides the following parameter control
use ;
let svd: SvdRec = svdLAS2?;
SVD Examples
SVD using R
$ Rscript -e 'options(digits=12);m<-matrix(1:9,nrow=3)^2;print(m);r<-svd(m);print(r);r$u%*%diag(r$d)%*%t(r$v)'
• The input matrix: M
[,1] [,2] [,3]
[1,] 1 16 49
[2,] 4 25 64
[3,] 9 36 81
• The diagonal matrix (singular values): S
$d
[1] 123.676578742544 6.084527896514 0.287038004183
• The left singular vectors: U
$u
[,1] [,2] [,3]
[1,] -0.415206840886 -0.753443585619 -0.509829424976
[2,] -0.556377565194 -0.233080213641 0.797569820742
[3,] -0.719755016815 0.614814099788 -0.322422608499
• The right singular vectors: V
$v
[,1] [,2] [,3]
[1,] -0.0737286909592 0.632351847728 -0.771164846712
[2,] -0.3756889918995 0.698691000150 0.608842071210
[3,] -0.9238083467338 -0.334607272761 -0.186054055373
• Recreating the original input matrix: r$u %*% diag(r$d) %*% t(r$v)
[,1] [,2] [,3]
[1,] 1 16 49
[2,] 4 25 64
[3,] 9 36 81
SVD using svdlibrs
• Cargo.toml dependencies
[dependencies]
svdlibrs = "0.5.1"
nalgebra-sparse = "0.9.0"
ndarray = "0.15.6"
extern crate ndarray;
use *;
use ;
use svd_dim_seed;
Output
svd.d = 3
U =
[[-0.4152068408862081, -0.7534435856189199, -0.5098294249756481],
[-0.556377565193878, -0.23308021364108839, 0.7975698207417085],
[-0.719755016814907, 0.6148140997884891, -0.3224226084985998]], shape=[3, 3], strides=[1, 3], layout=Ff (0xa), const ndim=2
S =
[123.67657874254405, 6.084527896513759, 0.2870380041828973], shape=[3], strides=[1], layout=CFcf (0xf), const ndim=1
V =
[[-0.07372869095916511, 0.6323518477280158, -0.7711648467120451],
[-0.3756889918994792, 0.6986910001499903, 0.6088420712097343],
[-0.9238083467337805, -0.33460727276072516, -0.18605405537270261]], shape=[3, 3], strides=[1, 3], layout=Ff (0xa), const ndim=2
The full Result<SvdRec> for above example looks like this:
svd = Ok(
SvdRec {
d: 3,
ut: [[-0.4152068408862081, -0.556377565193878, -0.719755016814907],
[-0.7534435856189199, -0.23308021364108839, 0.6148140997884891],
[-0.5098294249756481, 0.7975698207417085, -0.3224226084985998]], shape=[3, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2,
s: [123.67657874254405, 6.084527896513759, 0.2870380041828973], shape=[3], strides=[1], layout=CFcf (0xf), const ndim=1,
vt: [[-0.07372869095916511, -0.3756889918994792, -0.9238083467337805],
[0.6323518477280158, 0.6986910001499903, -0.33460727276072516],
[-0.7711648467120451, 0.6088420712097343, -0.18605405537270261]], shape=[3, 3], strides=[3, 1], layout=Cc (0x5), const ndim=2,
diagnostics: Diagnostics {
non_zero: 9,
dimensions: 3,
iterations: 3,
transposed: false,
lanczos_steps: 3,
ritz_values_stabilized: 3,
significant_values: 3,
singular_values: 3,
end_interval: [
-1e-30,
1e-30,
],
kappa: 1e-6,
random_seed: 3141,
},
},
)