關於C++ armadillo 矩陣庫報錯 warning: svd(): decomposition failed的問題
阿新 • • 發佈:2018-11-16
查錯流程:
首先說明一下博主用的版本是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了吧。