【问题标题】:How do I get an Armadillo function to NOT print an error when inverting a singular matrix?如何在反转奇异矩阵时让犰狳函数不打印错误?
【发布时间】:2015-03-09 19:36:12
【问题描述】:

我和一个朋友正在开发一个 R 包,并将 RcppArmadillo 包用于一些更重的矩阵代数。到目前为止一切都很顺利,但我们在矩阵求逆方面遇到了一些小问题。长话短说,一个程序正在搜索一种特定类型的矩阵,并且必须检查更新矩阵的逆矩阵是否存在于循环的每次迭代中(逆矩阵本身也是需要的)。现在我们正在使用函数inv(A, B),它返回一个布尔值,指示矩阵B是否可逆(如果不是,A设置为0x0矩阵,否则A = inv(B))。如果这个函数没有打印错误,那对我们来说会很好,因为返回的布尔值为循环提供了正确进行所需的信息。似乎只是打印了一个错误,而不是“抛出”,如下程序所示:

#include <iostream>
#include <armadillo>

using namespace std;
using namespace arma;

int main(int argc, char** argv)
{
    mat A = randu<mat>(5,5);
    mat B = zeros<mat>(5,5);

    inv(A, B);

    cout << A << "error printed but not fatal" << endl;

    A = inv(B);

    cout << A << "never make it this far" << endl;

    return 0;
}

导致:

Johns-MacBook-Pro:test johnsherrill$ g++ armaExample.cpp -o example -O2 -larmadillo
Johns-MacBook-Pro:test johnsherrill$ ./example

error: inv(): matrix appears to be singular

[matrix size: 0x0]
error printed but not fatal

error: inv(): matrix appears to be singular

terminate called after throwing an instance of 'std::runtime_error'
  what():  inv(): matrix appears to be singular
Abort trap: 6

有没有办法在不首先单独检查 B 是否可逆的情况下解决这个问题?这种类型的错误也会在 R 中打印出来。

【问题讨论】:

    标签: c++ r rcpp armadillo


    【解决方案1】:

    最简单的方法是在包含 Armadillo 标头之前定义 ARMA_DONT_PRINT_ERRORS。

    例如:

    #define ARMA_DONT_PRINT_ERRORS
    #include <armadillo>   // or #include <RcppArmadillo.h> if you're using Rcpp
    

    定义在 http://arma.sourceforge.net/docs.html#config_hpp

    【讨论】:

    • 感谢您指出这些#defines。显然我没有足够的“声誉点”来支持答案,但如果我这样做了,是否认为堆栈溢出可以支持多个答案?我认为@nrussell 的回答也很有帮助。
    • 这很危险。犰狳警告您有关数字错误是有充分理由的。 [而且你总是可以投票,但只接受一个答案。 ]
    • @DirkEddelbuettel 我明白了,但如果我发现异常并编写自己的错误消息,那对用户不是更有用吗?
    【解决方案2】:

    基于API documentation 中的示例,使用arma::set_stream_err2 可能是这样的:

    #include <RcppArmadillo.h>
    // [[Rcpp::depends(RcppArmadillo)]]
    
    // [[Rcpp::export]]
    void arma_invert() {
    
      std::ostream nullstream(0);
      arma::set_stream_err2(nullstream);
    
      arma::mat A = arma::randu<arma::mat>(5,5);
      arma::mat B = arma::zeros<arma::mat>(5,5);
      bool flag = arma::inv(A, B);
    
      if (!flag) {
        Rcpp::Rcout << 
          A << "error printed but not fatal" << std::endl;
      } else {
        A = arma::inv(B);
        Rcpp::Rcout <<
          A << "never make it this far" << std::endl; 
      }
    }
    

    产生

    [matrix size: 0x0]
    error printed but not fatal
    

    而不是

    error: inv(): matrix appears to be singular
    
    [matrix size: 0x0]
    error printed but not fatal
    

    或者使用您的 CLI 示例,

    #include <iostream>
    #include <armadillo>
    
    int main(int argc, char** argv) {
    
      std::ostream nullstream(0);
      arma::set_stream_err2(nullstream);
    
      arma::mat A = arma::randu<arma::mat>(5,5);
      arma::mat B = arma::zeros<arma::mat>(5,5);
      bool flag = arma::inv(A, B);
    
      if (!flag) {
        std::cout <<
          A << "error printed but not fatal" << std::endl;
      } else {
        A = arma::inv(B);
        std::cout <<
          A << "never make it this far" << std::endl;
      }
    
     return 0;
    }
    

    [nathan@nrussell tmp]$ g++ example.cpp -o example -O2 -I /home/nathan/R/x86_64-redhat-linux-gnu-library/3.1/RcppArmadillo/include -lblas -llapack
    [nathan@nrussell tmp]$ ./example
    [matrix size: 0x0]
    error printed but not fatal
    

    【讨论】:

    • 有一个更简单的方法:#define ARMA_DONT_PRINT_ERRORS 在包含 Armadillo 或 RcppArmadillo 头文件之前。
    • @mtall 谢谢,我不确定该声明应该放在哪里。
    【解决方案3】:

    通过浏览犰狳的来源,我看到的唯一直接的方法是在armadillo_bits/config.hpp 中注释掉#define ARMA_PRINT_ERRORS 行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多