我正在尝试计算矩阵的 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 矩阵,在这种情况下它应该是单位矩阵,缺失的向量在哪里???
免责声明:我不是数学专家。因此,请对这个答案中的所有内容持保留态度,它仅代表我自己对这个主题的理解。
MxN SVD 分解没有唯一定义。您的
1,0,0
示例有点过于简单,无法理解正在发生的情况,因此我将使用以下矩阵:
根据网上资源,SVD分解应该是:
请注意,红色数字绝对没有任何意义,因为它们会与
0
相乘。所以都可以用0
代替。此外,它们甚至对最终矩阵没有影响,所以我们可以简单地完全删除它们。
这正是 nalgebra 所做的,它的 SVD 结果是:
use nalgebra::*;
fn main() {
let x = dmatrix![
1.,2.,3.;
4.,5.,6.
];
let svd = x.svd(true, true);
let u = svd.u.unwrap();
let e = svd.singular_values;
let v_t = svd.v_t.unwrap();
println!("U: {}", u);
println!("Σ: {}", e);
println!("V_t: {}", v_t);
}
U:
┌ ┐
│ 0.38631770311861147 0.9223657800770584 │
│ 0.9223657800770584 -0.38631770311861147 │
└ ┘
Σ:
┌ ┐
│ 9.508032000695726 │
│ 0.7728696356734843 │
└ ┘
V_t:
┌ ┐
│ 0.42866713354862646 0.5663069188480351 0.7039467041474435 │
│ -0.8059639085892969 -0.1123824140965934 0.5811990803961106 │
└ ┘
从性能角度来看这样做是有意义的;结果中的值并不意味着任何内容都可以优化。
当然,他们的方法的缺点是,
U
和V
矩阵不再是有效的旋转矩阵。它们是否必须可能取决于问题。