#svd #algorithm #matrix #version #diagnostics #data #svdlibc

single-svdlib

A Rust port of LAS2 from SVDLIBC

2 unstable releases

0.2.0 Mar 14, 2025
0.1.0 Dec 23, 2024

#241 in Algorithms

Download history 105/week @ 2024-12-18 25/week @ 2024-12-25 4/week @ 2025-01-01 8/week @ 2025-01-08 9/week @ 2025-01-22 9/week @ 2025-01-29 14/week @ 2025-02-05 17/week @ 2025-02-12 14/week @ 2025-02-19 10/week @ 2025-02-26 8/week @ 2025-03-05 130/week @ 2025-03-12 13/week @ 2025-03-19

162 downloads per month
Used in 2 crates (via single_algebra)

Custom license

145KB
2.5K SLoC

single_svdlib

A Rust library for performing Singular Value Decomposition (SVD) on sparse matrices using the Lanczos algorithm. It is build on the original library and expan

Overview

svdlibrs is a Rust port of LAS2 from SVDLIBC, originally developed by Doug Rohde. This library efficiently computes SVD on sparse matrices, particularly large ones, and returns the decomposition as ndarray components.

This implementation extends the original svdlibrs by Dave Farnham with:

  • Updated dependency versions
  • Support for a broader range of numeric types (f64, f32, others)
  • Column masking capabilities for analyzing specific subsets of data

Features

  • Performs SVD on sparse matrices using the Lanczos algorithm
  • Works with various input formats: CSR, CSC, or COO matrices
  • Column masking for dimension selection without data copying
  • Generic implementation supporting different numeric types
  • High numerical precision for critical calculations

Installation

Add this to your Cargo.toml:

[dependencies]
single-svdlib = "0.1.0"
nalgebra-sparse = "0.10.0"
ndarray = "0.16.1"

Basic Usage

use single_svdlib::{svd, svd_dim, svd_dim_seed};
use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix};

// Create a sparse matrix
let mut coo = CooMatrix::<f64>::new(3, 3);
coo.push(0, 0, 1.0); coo.push(0, 1, 16.0); coo.push(0, 2, 49.0);
coo.push(1, 0, 4.0); coo.push(1, 1, 25.0); coo.push(1, 2, 64.0);
coo.push(2, 0, 9.0); coo.push(2, 1, 36.0); coo.push(2, 2, 81.0);

let csr = CsrMatrix::from(&coo);

// Compute SVD
let svd_result = svd(&csr)?;

// Access the results
println!("Rank: {}", svd_result.d);
println!("Singular values: {:?}", svd_result.s);
println!("Left singular vectors (U): {:?}", svd_result.ut.t());
println!("Right singular vectors (V): {:?}", svd_result.vt.t());

// Reconstruct the original matrix
let reconstructed = svd_result.recompose();

Column Masking

The library supports analyzing specific columns without copying the data:

use single_svdlib::{svd, MaskedCSRMatrix};
use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix};

// Create a sparse matrix
let mut coo = CooMatrix::<f64>::new(3, 5);
coo.push(0, 0, 1.0); coo.push(0, 2, 2.0); coo.push(0, 4, 3.0);
coo.push(1, 1, 4.0); coo.push(1, 3, 5.0);
coo.push(2, 0, 6.0); coo.push(2, 2, 7.0); coo.push(2, 4, 8.0);

let csr = CsrMatrix::from(&coo);

// Method 1: Using a boolean mask (true = include column)
let mask = vec![true, false, true, false, true]; // Only columns 0, 2, 4
let masked_matrix = MaskedCSRMatrix::new(&csr, mask);

// Method 2: Specifying which columns to include
let columns = vec![0, 2, 4];
let masked_matrix = MaskedCSRMatrix::with_columns(&csr, &columns);

// Run SVD on the masked matrix
let svd_result = svd(&masked_matrix)?;

Support for Different Numeric Types

The library supports various numeric types:

// With f64 (double precision)
let csr_f64 = CsrMatrix::<f64>::from(&coo);
let svd_result = svd(&csr_f64)?;

// With f32 (single precision)
let csr_f32 = CsrMatrix::<f32>::from(&coo);
let svd_result = svd(&csr_f32)?;

// With integer types (converted internally)
let csr_i32 = CsrMatrix::<i32>::from(&coo);
let masked_i32 = MaskedCSRMatrix::with_columns(&csr_i32, &columns);
let svd_result = svd(&masked_i32)?;

Advanced Usage

For more control over the SVD computation:

use single_svdlib::{svdLAS2, SvdRec};

// Customize the SVD calculation
let svd: SvdRec = svdLAS2(
    &matrix,        // sparse matrix
    dimensions,     // upper limit of desired dimensions (0 = max)
    iterations,     // number of algorithm iterations (0 = auto)
    &[-1.0e-30, 1.0e-30], // interval for unwanted eigenvalues
    1.0e-6,         // relative accuracy threshold
    random_seed,    // random seed (0 = auto-generate)
)?;

SVD Results and Diagnostics

The SVD results are returned in a SvdRec struct:

pub struct SvdRec {
    pub d: usize,        // Dimensionality (rank)
    pub ut: Array2<f64>, // Transpose of left singular vectors
    pub s: Array1<f64>,  // Singular values
    pub vt: Array2<f64>, // Transpose of right singular vectors
    pub diagnostics: Diagnostics, // Computational diagnostics
}

The Diagnostics struct provides detailed information about the computation:

pub struct Diagnostics {
    pub non_zero: usize,   // Number of non-zeros in the input matrix
    pub dimensions: usize, // Number of dimensions attempted
    pub iterations: usize, // Number of iterations attempted
    pub transposed: bool,  // True if the matrix was transposed internally
    pub lanczos_steps: usize,          // Number of Lanczos steps
    pub ritz_values_stabilized: usize, // Number of ritz values
    pub significant_values: usize,     // Number of significant values
    pub singular_values: usize,        // Number of singular values
    pub end_interval: [f64; 2], // Interval for unwanted eigenvalues
    pub kappa: f64,             // Relative accuracy threshold
    pub random_seed: u32,       // Random seed used
}

License

This library is provided under the BSD License, as per the original SVDLIBC implementation.

Acknowledgments

  • Dave Farnham for the original Rust port
  • Doug Rohde for the original SVDLIBC implementation
  • University of Tennessee Research Foundation for the underlying mathematical library

Dependencies

~5.5MB
~113K SLoC