纳尔代数的 SVD 分解表现得很奇怪

问题描述 投票:0回答:2

我正在尝试计算矩阵的 SVD,作为一个玩具示例,我使用了向量。

我运行了我的代码: 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);
}

我在崩溃之前得到了这个输出:

  ┌       ┐
  │ 1 0 0 │
  └       ┘


v

  ┌   ┐
  │ 1 │
  └   ┘


u

  ┌       ┐
  │ 1 0 0 │
  └       ┘

这是废话。根据定义,u 应该是一个 3x3 矩阵,在这种情况下它应该是单位矩阵,缺失的向量在哪里???

math rust linear-algebra computational-geometry nalgebra
2个回答
3
投票

我认为

nalgebra::linalg::SVD
似乎是一个性能优化版本,偏离了
MxN
矩阵的 SVD 的“经典”定义。

如果您想要这种行为,请使用

nalgebra_lapack::SVD
代替:

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 │
  └       ┘

3
投票

定义 SVD 的方法有很多种,其中一种可以让 U 跨越线性函数的范围(V 是其零空间的正交补)。所以这段代码返回了一个关于这样的定义的正确的 SVD。

这种简化公式的优点是,您不必为对矩阵 X 不起任何作用的空间部分发明一个基础。在这种情况下,您必须用以下基础来补充 U [1,0,0]^T 的正交补集以获得完整的 U。此外,该基可以是该二维空间的任意基。

© www.soinside.com 2019 - 2024. All rights reserved.