在RcppEigen中使用Boost高精度

时间:2018-10-18 09:29:33

标签: r boost eigen rcpp armadillo

我已经使用RcppArmadillo编写了一个库。我的问题是对于某些参数,arma :: solve函数无法提供确切的解决方案,因为“ A”矩阵的rcond接近于0。如果arma :: solve可以精确地求解线性方程,则不会有问题。但这给了我一个大概的解决方案,对我来说还不够。

然后,我考虑过使用RcppEigen,并使用boost多精度变量。如果我对Eigen的理解正确,那么Eigen求解器将为我提供一个多精度解决方案,而且该解决方案很可能对我来说足够好(即使使用float128)。

但是当我尝试实施该计划时,出现了一个错误,并且我不知道该怎么办。例如,以下作品:

#include <RcppArmadillo.h>
#include <RcppEigen.h>
#include <cmath>
#include <cstdint>
#include <boost/multiprecision/float128.hpp>
#include <boost/multiprecision/eigen.hpp>

// Correctly setup the build environment 
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(BH)]]
using namespace Rcpp;
using namespace arma;
using namespace Eigen;
using namespace boost;
using namespace boost::multiprecision;
using Eigen::Map;
using Eigen::MatrixXd;                  // variable size matrix, double precision
using Eigen::VectorXd;
using Eigen::Matrix;
using Eigen::Dynamic;
namespace mp = boost::multiprecision;


    // [[Rcpp::export]]
    Eigen::MatrixXd onesfgh_LPPLS_RcppEigen(int t2, int t1, double tc, double m, double w) {
      //Definitions & pre-computations:
      unsigned int tdim;
      double ttc, powttc, wlog, sinwlog, coswlog;
      tdim = t2 - t1 + 1;
      ttc = tc - t1 + 1;
      Eigen::MatrixXd output(tdim, 4); //first dimension is time, second is onesfgh
      //Main calculations:
      for (unsigned int i = 0; i < tdim; i++) {
        output(i, 0) = 1.0;
        ttc--;
        powttc = pow(ttc, m);
        wlog = w * log(ttc);
        sinwlog = sin(wlog);
        coswlog = cos(wlog);
        //sincos(wlog, &sinwlog, &coswlog);
        output(i, 1) = powttc;
        output(i, 2) = coswlog * powttc;
        output(i, 3) = sinwlog * powttc;
      }
      return output;
    }

但是:

// [[Rcpp::export]]
Eigen::Matrix<boost::multiprecision::number<boost::multiprecision::float128, boost::multiprecision::et_off>, Eigen::Dynamic, 4> onesfgh_LPPLS_RcppEigen(int t2, int t1, double tc, double m, double w) {
  //Definitions & pre-computations:
  unsigned int tdim;
  boost::multiprecision::number<boost::multiprecision::float128, boost::multiprecision::et_off> tc128(tc), m128(m), w128(w);
  boost::multiprecision::number<boost::multiprecision::float128, boost::multiprecision::et_off> ttc, powttc, wlog, sinwlog, coswlog;
  boost::multiprecision::number<boost::multiprecision::float128, boost::multiprecision::et_off> t1128(double(t1));
  tdim = t2 - t1 + 1;
  ttc = tc128 - t1128 + 1.0;
  Eigen::Matrix<boost::multiprecision::number<boost::multiprecision::float128, boost::multiprecision::et_off>, Eigen::Dynamic, 4> output(tdim, 4); //first dimension is time, second is onesfgh
  //Main calculations:
  for (unsigned int i = 0; i < tdim; i++) {
    output(i, 0) = 1.0;
    ttc--;
    powttc = boost::multiprecision::pow(ttc, m128);
    wlog = w128 * boost::multiprecision::log(ttc);
    sinwlog = boost::multiprecision::sin(wlog);
    coswlog = boost::multiprecision::cos(wlog);
    //sincos(wlog, &sinwlog, &coswlog);
    output(i, 1) = powttc;
    output(i, 2) = coswlog * powttc;
    output(i, 3) = sinwlog * powttc;
  }
  return output;
}

它不起作用。我收到错误消息:

RcppExports.cpp:11:15: error: 'boost' was not declared in this scope

尤其是,我尝试了https://www.boost.org/doc/libs/1_60_0/libs/math/doc/html/math_toolkit/high_precision/using_test.html中给出的建议,但没有使用typedef,因为在另一篇文章中,Dirk Eddelbuettel建议typedef并不容易处理(它们应该放在另一个.h文件中)。 )。

有什么建议吗?

编辑:

我通过不导出修改了功能。现在的代码是:

  #include <RcppArmadillo.h>
    #include <RcppEigen.h>
    #include <cmath>
    #include <cstdint>
    #include <boost/multiprecision/float128.hpp>
    #include <boost/multiprecision/eigen.hpp>

    // Correctly setup the build environment 
    // [[Rcpp::depends(RcppArmadillo)]]
    // [[Rcpp::depends(RcppEigen)]]
    // [[Rcpp::depends(BH)]]
    using namespace Rcpp;
    using namespace arma;
    using namespace Eigen;
    using namespace boost;
    using namespace boost::multiprecision;
    using Eigen::Map;
    using Eigen::MatrixXd;                  
    using Eigen::VectorXd;
    using Eigen::Matrix;
    using Eigen::Dynamic;
    namespace mp = boost::multiprecision;

    Eigen::Matrix<mp::float128, Eigen::Dynamic, 4> onesfgh_LPPLS_RcppEigen(int `t2, int t1, double tc, double m, double w) {`
      //Definitions & pre-computations:
      unsigned int tdim;
      mp::float128 tc128(tc), m128(m), w128(w);
      mp::float128 ttc, powttc, wlog, sinwlog, coswlog;
      mp::float128 t1128(double(t1));
      tdim = t2 - t1 + 1;
      ttc = tc128 - t1128 + 1.0;
      Eigen::Matrix<mp::float128, Eigen::Dynamic, 4> output(tdim, 4); 
      //Main calculations:
      for (unsigned int i = 0; i < tdim; i++) {
        output(i, 0) = 1.0;
        ttc--;
        powttc = mp::pow(ttc, m128);
        wlog = w128 * mp::log(ttc);
        sinwlog = mp::sin(wlog);
        coswlog = mp::cos(wlog);
        //sincos(wlog, &sinwlog, &coswlog);
        output(i, 1) = powttc;
        output(i, 2) = coswlog * powttc;
        output(i, 3) = sinwlog * powttc;
      }
      return output;
    }

现在我收到以下错误消息:

babel_RcppArmadillo.cpp:6:42: fatal error: boost/multiprecision/eigen.hpp: 
No such file or directory
#include <boost/multiprecision/eigen.hpp>                                          
compilation terminated.

这很奇怪,因为我认为BH包含boost的子文件夹。

1 个答案:

答案 0 :(得分:3)

更新:由于BH package包含自2019年1月以来的必需标头,因此现在应该没有必要。


version 1.68中添加了boost/multiprecision/eigen.hpp标头,而BH package当前提供了1.66的提升。您必须单独安装更新的增强。以下应该可以使用,但未经测试:

  1. 下载boost 1.68并将其解压缩到合适的目录中。在Linux和其他类似Unix的系统上,我可能会使用/usr/local/include。否则,我将使用名称中没有空格的任何路径。
  2. 不要依赖BH软件包,即为// [[Rcpp::depends(BH)]]等删除sourceCpp。或Imports: BH供软件包使用。
  3. 如果在步骤1中将boost安装在非标准位置,则必须告诉编译器去那里。这可以通过

    PKG_CPPFLAGS=-I<path-to-boost>
    

    通过Sys.setenv进行sourceCpp等。或在src/Makevars(.win)中以供软件包使用。