rcpp包编译过程映射到cxxfunction编译

huangapple go评论86阅读模式
英文:

rcpp package compilation process map to cxxfunction compilation

问题

我编写了一个R包,该包使用Rcpp和RcppEigen编译用户编写的C++代码。用户每次想要创建新模型时,必须编写三个文件:

目前,所有三个文件都保存在src/目录中,通过调用devtools::load_all(".")触发编译。编译后,可从R调用的函数将导出到NAMESPACE这个包的所有内容都能成功编译

不幸的是,我认为我设计了这个包错误。我希望用户经常更改这些文件,不同的用户创建的模型可能与其他用户不同。因此,我想将这些文件保存在包目录之外(很容易),并使用cxxfunplus::cxxfunctionplus()编译用户编写的代码(我从RStan的rstan::stan_model()中借鉴了这个想法)。我还根据他们的内联插件编写了我的内联插件

那么我的包编译如何映射到cxxfunction的编译?

我的当前尝试如下,但我相当确定这是错误的。我收到的错误消息是

Error in compileCode(f, code, language = language, verbose = verbose) : 
  file25a041c179ba.cpp:12:10: fatal error: pf/include/pf/bootstrap_filter_with_covariates.h: No such file or directory   12 | #include "pf/include/pf/bootstrap_filter_with_covariates.h" // the boostrap particle filter      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~compilation terminated.make: *** [/usr/lib/R/etc/Makeconf:177: file25a041c179ba.o] Error 1

Stan在他们的插件中有一行类似于这样的,可以找到所有他们的头文件(例如system.file("include", "stan", "math", "prim", package = "StanHeaders", mustWork = TRUE))。然而,我的包的头文件似乎没有安装到该目录中的任何位置。为什么我的头文件没有安装?

src <- r"(// 替换每个实例的<TODO>与您自己的代码!

#include "svol_leverage_bswc.h"

Svol_leverageBSWC::Svol_leverageBSWC(double phi, double mu, double sigma, double rho)
{
  m_params << phi, mu, sigma, rho;
}


auto Svol_leverageBSWC::q1Samp(const ovec &y1, const cvec& z1) -> svec
{
  // phi, mu, sigma, rho
  svec x1samp;
  x1samp(0) = m_example_stdNormSampler.sample() * m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0));
  return x1samp;
}

// ... 省略其余部分

thisMod <- cxxfunplus::cxxfunctionplus(signature(), body = body, plugin = "pfr", includes = header, verbose = T)
英文:

I wrote an R package that compiles user-written c++ code with the help of Rcpp and RcppEigen. Every time the user wants to create a new model, he/she must write three files:

Currently, all three files are saved in the src/ directory, and compilation is triggered by calling devtools::load_all(".") After compilation, the functions callable from R are exported to NAMESPACE. Everything compiles just fine in this package framework.

Unfortunately, though, I think I designed this package incorrectly. I expect the users to change these files frequently, and different users to create different models than other users. So, I would like to save these files outside of the package directory (easy), and to compile user-written code with cxxfunplus::cxxfunctionplus() (I stole this idea from RStan's rstan::stan_model()). I also wrote my inline plugin based off of their inline plugin.

So how does my package compilation map to cxxfunction compilation?

My current attempt is below, but I'm pretty sure this is way off. The error I'm getting is

Error in compileCode(f, code, language = language, verbose = verbose) : 
  file25a041c179ba.cpp:12:10: fatal error: pf/include/pf/bootstrap_filter_with_covariates.h: No such file or directory   12 | #include "pf/include/pf/bootstrap_filter_with_covariates.h" // the boostrap particle filter      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~compilation terminated.make: *** [/usr/lib/R/etc/Makeconf:177: file25a041c179ba.o] Error 1

Stan has a line like this in their plugin that finds all their header files (e.g. system.file("include", "stan", "math", "prim", package = "StanHeaders", mustWork = TRUE)). However, my package's header files don't appear to be installed anywhere in that same directory. Why don't my headers get installed?

src <- r"(// replace every instance of <TODO> with your own code! 

#include "svol_leverage_bswc.h" 

Svol_leverageBSWC::Svol_leverageBSWC(double phi, double mu, double sigma, double rho)
{
  m_params << phi, mu, sigma, rho;
}


auto Svol_leverageBSWC::q1Samp(const ovec &y1, const cvec& z1) -> svec
{
  // phi, mu, sigma, rho
  svec x1samp;
  x1samp(0) = m_example_stdNormSampler.sample() * m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0));
  return x1samp;
}


auto Svol_leverageBSWC::fSamp(const svec &xtm1, const cvec& zt) -> svec
{
  // phi, mu, sigma, rho
  svec xt;
  double mean = m_params(1) + m_params(0) * (xtm1(0) - m_params(1)) +
    zt(0) * m_params(3) * m_params(2) * std::exp(-.5 * xtm1(0));
  xt(0) = mean + m_example_stdNormSampler.sample() * m_params(2) * std::sqrt(1.0 - m_params(3) * m_params(3));
  return xt;
}


double Svol_leverageBSWC::logGEv(const ovec &yt, const svec &xt, const cvec& zt)
{
  return rveval::evalUnivNorm<double>(
    yt(0),
    0.0,
    std::exp(.5 * xt(0)),
    true);
}



double Svol_leverageBSWC::logMuEv(const svec &x1, const cvec& z1)
{
  // parameter order phi, mu, sigma, rho
  return rveval::evalUnivNorm<double>(
    x1(0),
    0.0,
    m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0)),
    true);
}


double Svol_leverageBSWC::logQ1Ev(const svec &x1, const ovec &y1, const cvec& z1)
{
  // parameter order phi, mu, sigma, rho
  return rveval::evalUnivNorm<double>(
    x1(0),
    0.0,
    m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0)),
    true);	
}
)"

header <- r"(// replace every instance of <TODO> with your own code! 

#ifndef SVOL_LEVERAGE_BSWC_H
#define SVOL_LEVERAGE_BSWC_H

#include "pf/include/pf/bootstrap_filter_with_covariates.h" // the boostrap particle filter
#include "pf/include/pf/rv_samp.h" 			                    // for sampling random numbers
#include "pf/include/pf/rv_eval.h" 			                    // for evaluating densities and pmfs
#include "pf/include/pf/resamplers.h" 		                  // for resampling classes

using namespace pf;
using namespace pf::filters;
using namespace pf::resamplers;

#define nparts_SVOL_LEVERAGE_BSWC 500    // number of particles
#define dimstate_SVOL_LEVERAGE_BSWC 1  // dimension of state vectors
#define dimobs_SVOL_LEVERAGE_BSWC 1    // dimension of observation vectors
#define dimcov_SVOL_LEVERAGE_BSWC 1    // dimension of covariate vectors
#define dimparam_SVOL_LEVERAGE_BSWC 4  // dimension of parameters

// helper type aliases
using resampT   = mn_resamp_fast1<nparts_SVOL_LEVERAGE_BSWC,dimstate_SVOL_LEVERAGE_BSWC,double>;
using svec      = Eigen::Matrix  <double, dimstate_SVOL_LEVERAGE_BSWC,1>;
using ovec      = Eigen::Matrix  <double, dimobs_SVOL_LEVERAGE_BSWC,1>;
using cvec      = Eigen::Matrix  <double, dimcov_SVOL_LEVERAGE_BSWC,1>;
using param_vec = Eigen::Matrix  <double, dimparam_SVOL_LEVERAGE_BSWC,1>;
using DynMat    = Eigen::Matrix  <double, Eigen::Dynamic, Eigen::Dynamic>;
using func      = std::function  <const DynMat(const svec&, const cvec&)>;
using BasePF    = BSFilterWC     <nparts_SVOL_LEVERAGE_BSWC, dimstate_SVOL_LEVERAGE_BSWC, dimobs_SVOL_LEVERAGE_BSWC, dimcov_SVOL_LEVERAGE_BSWC, resampT, double, true>;


/**
 * @brief a particle filter class template for a TODO model
 *
 */
class Svol_leverageBSWC : public BasePF
{
private:

  // example parameter
  param_vec m_params;

  // use this for sampling
  rvsamp::UnivNormSampler<double> m_example_stdNormSampler; 
  
  // required by algorithm and required to define your model
  double logQ1Ev (const svec &x1,   const ovec &y1,  const cvec &z1 );
  double logMuEv (const svec &x1,   const cvec &z1                  );
  double logGEv  (const ovec &yt,   const svec &xt,  const cvec& zt );
  auto   q1Samp  (const ovec &y1,   const cvec& z1                  ) -> svec;
  auto   fSamp   (const svec &xtm1, const cvec &zt                  ) -> svec;
  
public:

  // constructor
  Svol_leverageBSWC(double phi, double mu, double sigma, double rho);
  
};

#endif  // SVOL_LEVERAGE_BSWC_H)"

#   //' @useDynLib pfr, .registration = TRUE
# //' @import RcppEigen
#   //' @importFrom Rcpp evalCpp
# //' @export
#   // [[Rcpp::export]]
#   double svol_leverage_bswc_approx_LL(const Rcpp::NumericVector& obsTS, const Rcpp::NumericVector& params){
#     
    
body <- r"(
  // instantiate model with arg params
  Svol_leverageBSWC mod(params[0],params[1],params[2],params[3]);

  // calculate likelihood by iterating through time series
  double ans(0.0);
  ovec yt, ytm1;
  for (int i = 1; i < obsTS.length(); i++){
    yt << obsTS[i]; ytm1 << obsTS[i-1];
    mod.filter(yt, ytm1);
    ans += mod.getLogCondLike();
  }
  return ans;
)"



#inline::registerPlugin("pfr", pfrplugin)
thisMod <- cxxfunplus::cxxfunctionplus(signature(), body = body, plugin = "pfr", includes = header, verbose = T)

答案1

得分: 0

根据Rcpp模块文档并将所有内容放入includes=中,代码可以正常运行:

inc <- r"(
#ifndef SVOL_LEVERAGE_BSWC_H
#define SVOL_LEVERAGE_BSWC_H

#include "pf/bootstrap_filter_with_covariates.h" // the boostrap particle filter
#include "pf/rv_samp.h" 			                    // for sampling random numbers
#include "pf/rv_eval.h" 			                    // for evaluating densities and pmfs
#include "pf/resamplers.h" 		                  // for resampling classes

using namespace pf;
using namespace pf::filters;
using namespace pf::resamplers;

#define nparts_SVOL_LEVERAGE_BSWC 500    // number of particles
#define dimstate_SVOL_LEVERAGE_BSWC 1  // dimension of state vectors
#define dimobs_SVOL_LEVERAGE_BSWC 1    // dimension of observation vectors
#define dimcov_SVOL_LEVERAGE_BSWC 1    // dimension of covariate vectors
#define dimparam_SVOL_LEVERAGE_BSWC 4  // dimension of parameters

// helper type aliases
using resampT   = mn_resamp_fast1<nparts_SVOL_LEVERAGE_BSWC,dimstate_SVOL_LEVERAGE_BSWC,double>;
using svec      = Eigen::Matrix  <double, dimstate_SVOL_LEVERAGE_BSWC,1>;
using ovec      = Eigen::Matrix  <double, dimobs_SVOL_LEVERAGE_BSWC,1>;
using cvec      = Eigen::Matrix  <double, dimcov_SVOL_LEVERAGE_BSWC,1>;
using param_vec = Eigen::Matrix  <double, dimparam_SVOL_LEVERAGE_BSWC,1>;
using DynMat    = Eigen::Matrix  <double, Eigen::Dynamic, Eigen::Dynamic>;
using func      = std::function  <const DynMat(const svec&, const cvec&)>;
using BasePF    = BSFilterWC     <nparts_SVOL_LEVERAGE_BSWC, dimstate_SVOL_LEVERAGE_BSWC, dimobs_SVOL_LEVERAGE_BSWC, dimcov_SVOL_LEVERAGE_BSWC, resampT, double, true>;

/**
 * @brief a particle filter class template for a TODO model
 *
 */
class Svol_leverageBSWC : public BasePF
{
private:

  // example parameter
  param_vec m_params;

  // use this for sampling
  rvsamp::UnivNormSampler<double> m_example_stdNormSampler; 
  
  // required by algorithm and required to define your model
  double logQ1Ev (const svec &x1,   const ovec &y1,  const cvec &z1 );
  double logMuEv (const svec &x1,   const cvec &z1                  );
  double logGEv  (const ovec &yt,   const svec &xt,  const cvec& zt );
  auto   q1Samp  (const ovec &y1,   const cvec& z1                  ) -> svec;
  auto   fSamp   (const svec &xtm1, const cvec &zt                  ) -> svec;
  
public:

  // constructor
  Svol_leverageBSWC(double phi, double mu, double sigma, double rho);
  
};

#endif  // SVOL_LEVERAGE_BSWC_H
  
  
double svol_leverage_bswc_approx_LL(const Rcpp::NumericVector& obsTS, const Rcpp::NumericVector& params){

    // instantiate model with arg params
  Svol_leverageBSWC mod(params[0],params[1],params[2],params[3]);

  // calculate likelihood by iterating through time series
  double ans(0.0);
  ovec yt, ytm1;
  for (int i = 1; i < obsTS.length(); i++){
    yt << obsTS[i]; ytm1 << obsTS[i-1];
    mod.filter(yt, ytm1);
    ans += mod.getLogCondLike();
  }
  return ans;
  
}

Svol_leverageBSWC::Svol_leverageBSWC(double phi, double mu, double sigma, double rho)
{
  m_params << phi, mu, sigma, rho;
}


auto Svol_leverageBSWC::q1Samp(const ovec &y1, const cvec& z1) -> svec
{
  // phi, mu, sigma, rho
  svec x1samp;
  x1samp(0) = m_example_stdNormSampler.sample() * m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0));
  return x1samp;
}


auto Svol_leverageBSWC::fSamp(const svec &xtm1, const cvec& zt) -> svec
{
  // phi, mu, sigma, rho
  svec xt;
  double mean = m_params(1) + m_params(0) * (xtm1(0) - m_params(1)) +
    zt(0) * m_params(3) * m_params(2) * std::exp(-.5 * xtm1(0));
  xt(0) = mean + m_example_stdNormSampler.sample() * m_params(2) * std::sqrt(1.0 - m_params(3) * m_params(3));
  return xt;
}


double Svol_leverageBSWC::logGEv(const ovec &yt, const svec &xt, const cvec& zt)
{
  return rveval::evalUnivNorm<double>(
    yt(0),
    0.0,
    std::exp(.5 * xt(0)),
    true);
}


double Svol_leverageBSWC::logMuEv(const svec &x1, const cvec& z1)
{
  // parameter order phi, mu, sigma, rho
  return rveval::evalUnivNorm<double>(
    x1(0),
    0.0,
    m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0)),
    true);
}


double Svol_leverageBSWC::logQ1Ev(const svec &x1, const ovec &y1, const cvec& z1)
{
  // parameter order phi, mu, sigma, rho
  return rveval::evalUnivNorm<double>(
    x1(0),
    

<details>
<summary>英文:</summary>

Following the [Rcpp modules vignette](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-modules.pdf) and jamming it all in `includes=` works:


inc <- r"(
#ifndef SVOL_LEVERAGE_BSWC_H
#define SVOL_LEVERAGE_BSWC_H

#include "pf/bootstrap_filter_with_covariates.h" // the boostrap particle filter
#include "pf/rv_samp.h" // for sampling random numbers
#include "pf/rv_eval.h" // for evaluating densities and pmfs
#include "pf/resamplers.h" // for resampling classes

using namespace pf;
using namespace pf::filters;
using namespace pf::resamplers;

#define nparts_SVOL_LEVERAGE_BSWC 500 // number of particles
#define dimstate_SVOL_LEVERAGE_BSWC 1 // dimension of state vectors
#define dimobs_SVOL_LEVERAGE_BSWC 1 // dimension of observation vectors
#define dimcov_SVOL_LEVERAGE_BSWC 1 // dimension of covariate vectors
#define dimparam_SVOL_LEVERAGE_BSWC 4 // dimension of parameters

// helper type aliases
using resampT = mn_resamp_fast1<nparts_SVOL_LEVERAGE_BSWC,dimstate_SVOL_LEVERAGE_BSWC,double>;
using svec = Eigen::Matrix <double, dimstate_SVOL_LEVERAGE_BSWC,1>;
using ovec = Eigen::Matrix <double, dimobs_SVOL_LEVERAGE_BSWC,1>;
using cvec = Eigen::Matrix <double, dimcov_SVOL_LEVERAGE_BSWC,1>;
using param_vec = Eigen::Matrix <double, dimparam_SVOL_LEVERAGE_BSWC,1>;
using DynMat = Eigen::Matrix <double, Eigen::Dynamic, Eigen::Dynamic>;
using func = std::function <const DynMat(const svec&, const cvec&)>;
using BasePF = BSFilterWC <nparts_SVOL_LEVERAGE_BSWC, dimstate_SVOL_LEVERAGE_BSWC, dimobs_SVOL_LEVERAGE_BSWC, dimcov_SVOL_LEVERAGE_BSWC, resampT, double, true>;

/**

  • @brief a particle filter class template for a TODO model
    *
    */
    class Svol_leverageBSWC : public BasePF
    {
    private:

// example parameter
param_vec m_params;

// use this for sampling
rvsamp::UnivNormSampler<double> m_example_stdNormSampler;

// required by algorithm and required to define your model
double logQ1Ev (const svec &x1, const ovec &y1, const cvec &z1 );
double logMuEv (const svec &x1, const cvec &z1 );
double logGEv (const ovec &yt, const svec &xt, const cvec& zt );
auto q1Samp (const ovec &y1, const cvec& z1 ) -> svec;
auto fSamp (const svec &xtm1, const cvec &zt ) -> svec;

public:

// constructor
Svol_leverageBSWC(double phi, double mu, double sigma, double rho);

};

#endif // SVOL_LEVERAGE_BSWC_H

double svol_leverage_bswc_approx_LL(const Rcpp::NumericVector& obsTS, const Rcpp::NumericVector& params){

// instantiate model with arg params

Svol_leverageBSWC mod(params[0],params[1],params[2],params[3]);

// calculate likelihood by iterating through time series
double ans(0.0);
ovec yt, ytm1;
for (int i = 1; i < obsTS.length(); i++){
yt << obsTS[i]; ytm1 << obsTS[i-1];
mod.filter(yt, ytm1);
ans += mod.getLogCondLike();
}
return ans;

}

Svol_leverageBSWC::Svol_leverageBSWC(double phi, double mu, double sigma, double rho)
{
m_params << phi, mu, sigma, rho;
}

auto Svol_leverageBSWC::q1Samp(const ovec &y1, const cvec& z1) -> svec
{
// phi, mu, sigma, rho
svec x1samp;
x1samp(0) = m_example_stdNormSampler.sample() * m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0));
return x1samp;
}

auto Svol_leverageBSWC::fSamp(const svec &xtm1, const cvec& zt) -> svec
{
// phi, mu, sigma, rho
svec xt;
double mean = m_params(1) + m_params(0) * (xtm1(0) - m_params(1)) +
zt(0) * m_params(3) * m_params(2) * std::exp(-.5 * xtm1(0));
xt(0) = mean + m_example_stdNormSampler.sample() * m_params(2) * std::sqrt(1.0 - m_params(3) * m_params(3));
return xt;
}

double Svol_leverageBSWC::logGEv(const ovec &yt, const svec &xt, const cvec& zt)
{
return rveval::evalUnivNorm<double>(
yt(0),
0.0,
std::exp(.5 * xt(0)),
true);
}

double Svol_leverageBSWC::logMuEv(const svec &x1, const cvec& z1)
{
// parameter order phi, mu, sigma, rho
return rveval::evalUnivNorm<double>(
x1(0),
0.0,
m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0)),
true);
}

double Svol_leverageBSWC::logQ1Ev(const svec &x1, const ovec &y1, const cvec& z1)
{
// parameter order phi, mu, sigma, rho
return rveval::evalUnivNorm<double>(
x1(0),
0.0,
m_params(2) / std::sqrt(1.0 - m_params(0) * m_params(0)),
true);
}

)"

inline::registerPlugin("pfr", pfrplugin)
yay <- cxxfunplus::cxxfunctionplus(signature(), plugin = "pfr", includes = inc)


</details>

huangapple
  • 本文由 发表于 2023年7月11日 07:50:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657957.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定