1. 程式人生 > >關於C++ armadillo 矩陣庫報錯 warning: svd(): decomposition failed的問題

關於C++ armadillo 矩陣庫報錯 warning: svd(): decomposition failed的問題

查錯流程:

首先說明一下博主用的版本是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了吧。