Search code examples
mathrustlinear-algebracomputational-geometrynalgebra

SVD decomposition of nalgebra is incomprehensible


I am trying to compute the SVD of matrices, as a toy example I used a vector.

I ran my code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=00110137fbcbda27c95e9d8791bb97cf

use nalgebra::*;

fn main() {
    let x = dmatrix![
        1., 0., 0.
    ];

    println!("{}", x);

    let svd = x.transpose().svd(true, true);

    // dbg!(&svd);

    let rank = svd.rank(1e-9);

    dbg!(rank);

    let x = svd.v_t.as_ref().unwrap().transpose();
    println!("v\n{}", svd.v_t.as_ref().unwrap().transpose());
    println!("u\n{}", svd.u.as_ref().unwrap().transpose());
    let null: OMatrix<_, _, _> = x.columns(rank, 3 - rank).clone_owned();

    println!("{}", null);
}

And I get this output before it crashes:

  ┌       ┐
  │ 1 0 0 │
  └       ┘


v

  ┌   ┐
  │ 1 │
  └   ┘


u

  ┌       ┐
  │ 1 0 0 │
  └       ┘

Which is nonsense. u should be a 3x3 matrix by definition, and it should be the identity matrix in this case, where are the missing vectors???


Solution

  • I think nalgebra::linalg::SVD seems to be a performance-optimized version that deviates from the 'classic' definition of an SVD for MxN matrices.

    If you want this behaviour, use nalgebra_lapack::SVD instead:

    use nalgebra::dmatrix;
    use nalgebra_lapack::SVD;
    
    fn main() {
        let x = dmatrix![1., 0., 0.];
    
        let svd = SVD::new(x).unwrap();
    
        println!("U: {}", svd.u);
        println!("Σ: {}", svd.singular_values);
        println!("V_t: {}", svd.vt);
    }
    
    U: 
      ┌   ┐
      │ 1 │
      └   ┘
    
    Σ: 
      ┌   ┐
      │ 1 │
      └   ┘
    
    V_t: 
      ┌       ┐
      │ 1 0 0 │
      │ 0 1 0 │
      │ 0 0 1 │
      └       ┘