关于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了吧。

猜你喜欢

转载自blog.csdn.net/yyhhlancelot/article/details/83414919
今日推荐