我正在尝试计算矩阵的 SVD,作为一个玩具示例,我使用了向量。
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 矩阵,在这种情况下它应该是单位矩阵,缺失的向量在哪里???
我认为
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 │
└ ┘
定义 SVD 的方法有很多种,其中一种可以让 U 跨越线性函数的范围(V 是其零空间的正交补)。所以这段代码返回了一个关于这样的定义的正确的 SVD。
这种简化公式的优点是,您不必为对矩阵 X 不起任何作用的空间部分发明一个基础。在这种情况下,您必须用以下基础来补充 U [1,0,0]^T 的正交补集以获得完整的 U。此外,该基可以是该二维空间的任意基。