查错流程:
首先说明一下博主用的版本是armadillo-9.100.5。目前未测试过其他版本是否会出现相同情况!!!
查看了一下源码:
template<typename T1>
inline
bool
svd
(
Mat<typename T1::elem_type>& U,
Col<typename T1::pod_type >& S,
Mat<typename T1::elem_type>& V,
const Base<typename T1::elem_type,T1>& X,
const char* method = "dc",
const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
)
{
arma_extra_debug_sigprint();
arma_ignore(junk);
arma_debug_check
(
( ((void*)(&U) == (void*)(&S)) || (&U == &V) || ((void*)(&S) == (void*)(&V)) ),
"svd(): two or more output objects are the same object"
);
const char sig = (method != NULL) ? method[0] : char(0);
arma_debug_check( ((sig != 's') && (sig != 'd')), "svd(): unknown method specified" );
// auxlib::svd() makes an internal copy of X
const bool status = (sig == 'd') ? auxlib::svd_dc(U, S, V, X) : auxlib::svd(U, S, V, X);
if(status == false)
{
U.soft_reset();
S.soft_reset();
V.soft_reset();
arma_debug_warn("svd(): decomposition failed");
}
return status;
}
我们可以注意到上方
arma_debug_warn("svd(): decomposition failed");
这就是错误来源。
接着看,是因为上方的条件判断语句
const bool status = (sig == 'd') ? auxlib::svd_dc(U, S, V, X) : auxlib::svd(U, S, V, X);
现在问题来了,这个sig到底是什么?现在我们只知道它有‘s’和‘d’两种。
我们去查阅官网文档,发现
The method argument is optional; method is either
"dc"
or"std"
"dc"
indicates divide-and-conquer method (default setting)"std"
indicates standard method- the divide-and-conquer method provides slightly different results than the standard method, but is considerably faster for large matrices
嗯,似乎发现了什么,'s'指的是"std"标准方法?'d'指的是"dc"分治方法?
关键是文档指出它默认的方法就是"dc"!!!
好的,现在我们的关键来了。
我现在感觉是因为默认sig( == 'd')
const bool status = (sig == 'd') ? auxlib::svd_dc(U, S, V, X) : auxlib::svd(U, S, V, X);
所以返回了 auxlib::svd_dc(U, S, V, X) ,它导致了我们失败,而这个东西已经被封装好了无法得知为什么会失败!
第一次实验:
int main()
{
mat temp = randu<mat>(176, 150);
mat U_test;
vec s_test;
mat V_test;
bool flag = arma::svd(U_test, s_test, V_test, temp);
}
很遗憾它会报错。
第二次实验:
int main()
{
mat temp = randu<mat>(176, 150);
mat U_test;
vec s_test;
mat V_test;
bool flag = arma::svd(U_test, s_test, V_test, temp,"dc");
}
虽然已经知道默认方式是"dc",不过还是想尝试一下,对,和想的一样报错了。
第三次实验:
int main()
{
mat temp = randu<mat>(176, 150);
mat U_test;
vec s_test;
mat V_test;
bool flag = arma::svd(U_test, s_test, V_test, temp,"std");
}
这次改成了"std",成功了!
个人总结:
armadillo-9.100.5下使用svd分解,默认的分治策略在小型的矩阵面前可以使用(我测试的方形矩阵,维度需要小于40),长方形矩阵就不一定了。而当维度过大,在默认的分治策略下就会报错。这时候需要改成"std"标准方法才可以顺利分解。应该也算这个矩阵库的一个小bug了吧。