如何使用C++;R中带有Rcpp的ODE解算器? < >为了评估速度在R和C++之间的ODE的差异,我在R:中建立了以下的ODE系统。 modelsir_cpp =function(t,x){ S = x[1] I1 = x[2] I2 = x[3] N=S+I1+I2 with(as.list(parm), { dS=B*I1-mu*S-beta*(S*(I1+I2)/N) dI1=beta*(S*(I1+I2)/N)-B*I1-lambda12*I1 dI2=lambda12*I1 res=c(dS,dI1,dI2) return(res) }) }

如何使用C++;R中带有Rcpp的ODE解算器? < >为了评估速度在R和C++之间的ODE的差异,我在R:中建立了以下的ODE系统。 modelsir_cpp =function(t,x){ S = x[1] I1 = x[2] I2 = x[3] N=S+I1+I2 with(as.list(parm), { dS=B*I1-mu*S-beta*(S*(I1+I2)/N) dI1=beta*(S*(I1+I2)/N)-B*I1-lambda12*I1 dI2=lambda12*I1 res=c(dS,dI1,dI2) return(res) }) },c++,r,rcpp,C++,R,Rcpp,为了解决这个问题,我使用了deSolve包 times = seq(0, 10, by = 1/52) parm=c(B=0.01,mu=0.008,beta=10,lambda12=1) xstart=c(S=900,I1=100,I2=0) out = as.data.frame(lsoda(xstart, times, modelsir, parm)) 这很有效。我尝试用C++求解器解决同一个系统,在R. Here中使用RCPP库是我添加的: #include <Rcpp.h>

为了解决这个问题,我使用了deSolve包

times = seq(0, 10, by = 1/52)
parm=c(B=0.01,mu=0.008,beta=10,lambda12=1)
xstart=c(S=900,I1=100,I2=0)
out = as.data.frame(lsoda(xstart, times, modelsir, parm))
这很有效。我尝试用C++求解器解决同一个系统,在R. Here中使用RCPP库是我添加的:

#include <Rcpp.h>
#include <boost/array.hpp>

// include Boost's odeint
#include <boost/numeric/odeint.hpp>

// [[Rcpp::depends(BH)]]

using namespace Rcpp;
using namespace std;
using namespace boost::numeric::odeint;

typedef boost::array< double ,3 > state_type;

// [[Rcpp::export]]
 Rcpp::NumericVector my_fun2(const Rcpp::NumericVector &x, const double t){
 Function f("modelsir_cpp");
    return f(_["t"]=t,_["x"]=x);
}
    void eqsir(const state_type &x, state_type &dxdt, const double t){
      Rcpp::NumericVector nvec=boost_array_to_nvec(x);
      Rcpp::NumericVector nvec2(3);
      nvec2=my_fun2(nvec,t);
      dxdt=nvec_to_boost_array(nvec2);
        }


void write_cout_2( const state_type &x , const double t ) {
  // use Rcpp's stream
  Rcpp::Rcout << t << '\t' << x[0] << '\t' << x[1] << '\t' << x[2] <<  endl;
}
typedef runge_kutta_dopri5< state_type > stepper_type;

// [[Rcpp::export]]
bool my_fun10_solver() {
  state_type x = { 900 , 100, 0 }; // initial conditions
  integrate_adaptive(make_controlled( 1E-12 , 1E-12 , stepper_type () ) ,
                     eqsir , x , 1.0 , 2 , 1/52 , write_cout_2 );
  return true;
}
#包括
#包括
//包括Boost的odeint
#包括
//[[Rcpp::Dependes(BH)]]
使用名称空间Rcpp;
使用名称空间std;
使用名称空间boost::numeric::odeint;
typedef boost::数组状态类型;
//[[Rcpp::导出]]
Rcpp::NumericVector my_fun2(常数Rcpp::NumericVector&x,常数双t){
函数f(“modelsir_cpp”);
返回f([“t”]=t,[“x”]=x);
}
无效等式(常数状态类型和x、状态类型和dxdt、常数双t){
Rcpp::NumericVector nvec=boost_array_to_nvec(x);
Rcpp::数值向量nvec2(3);
nvec2=my_fun2(nvec,t);
dxdt=nvec-to-boost-u阵列(nvec2);
}
无效写入权限2(常量状态类型&x,常量双t){
//使用Rcpp的流

Rcpp::Rcout你能试试下面的吗

integrate_adaptive(make_controlled( 1E-12 , 1E-12 , stepper_type () ) ,
                 eqsir , x , 1.0 , 2.0 , 1.0/52.0 , write_cout_2 );
不过有一些优化建议。你正在解一个ODE,这表明你是物理学家或工程师,这太棒了,我也是物理学家,物理学家简直棒极了

但计算机科学家也是如此,他们已经尽了最大的努力尽可能快地完成这件事。他们构建编译器,这带走了大量的思考。尽可能地帮助他们

为什么我要告诉你这些?回到ODE的事情。boost的自适应积分器可能正在调用
eqsir() <代码> 1E9< /代码> Times。尝试使该函数尽可能的性能。考虑重写<代码> MyuFun2,使<代码> x <代码>被改写而不是创建一个新的并返回它。<代码> x>代码>是最后一个状态。除非您想绘制动态图,否则您不会在意它。

void my_fun2(Rcpp::NumericVector &x, const double t);

必须在每个调用上分配新的内存。最后,考虑使用2个转换器,用于<代码> NVEC < /代码>和<代码> StaseYyType < /代码>,作为参考的第二个选项。您的新<代码> EQSIR 看起来是这样的,运行速度可能更快。

Rcpp::NumericVector nvec(3); // declared outside
void eqsir(const state_type &x, state_type &dxdt, const double t){
  boost_array_to_nvec(x, nvec);
  my_fun2(nvec,t);
  nvec_to_boost_array(nvec, dxdt);
}

它没有改进。请注意,我提到的上一个脚本工作正常,因此这意味着我的包工作正常。我想错误可能更多地出现在我的eqsir函数中。很高兴知道。不是这样。它抱怨函数的签名。让我更仔细地看一下。请检查更新的答案。不,weite_cout_2和eqsir似乎都很好。与b相同的错误以前?可能只是int现在是double或者其他什么。在C(++)中,
1/52
是一个整数,被截断为零,而
1.0/52.0
(或者其中一个是double
)是你想要的浮点表达式。欢迎C++,一种强类型的、超高效的编程语言。重要的位是强类型的部分。没有int的时间结构,它是1的类型,而不是1,这是一个双。Dirk再一次说:“快一点:”。
Rcpp::NumericVector nvec=boost_array_to_nvec(x);
Rcpp::NumericVector nvec2(3);
Rcpp::NumericVector nvec(3); // declared outside
void eqsir(const state_type &x, state_type &dxdt, const double t){
  boost_array_to_nvec(x, nvec);
  my_fun2(nvec,t);
  nvec_to_boost_array(nvec, dxdt);
}