Rcpp - 如何在 C++ 代码中使用分布函数
Rcpp - how to use a distribution function in the C++ code
我正在为 N(0,1) 分布编写 Metropolis-Hastings 算法:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector metropolis(int R, double b, double x0){
NumericVector y(R);
y(1) = x0;
for(int i=1; i<R; ++i){
y(i) = y(i-1);
double xs = y(i)+runif(1, -b,b)[0];
double a = dnorm(xs, 0, 1)[0]/dnorm(y(i), 0, 1)[0];
NumericVector A(2);
A(0) = 1;
A(1) = a;
double random = runif(1)[0];
if(random <= min(A)){
y[i] = xs;
}
}
return y;
}
但每次我尝试编译该函数时,都会出现此错误:
Line 12: no matching function for call to 'dnorm4'
我尝试使用 dnorm 编写一个简单的函数,例如
NumericVector den(NumericVector y, double a, double b){
NumericVector x = dnorm(y,a,b);
return x;
}
并且有效。有人知道为什么我在 Metropolis 代码中有这种类型的错误吗?
是否有一些其他方法可以像在 R 中那样在 C++ 代码中使用密度函数?
在 Rcpp 中有两组采样器 - 标量和矢量 - 按名称spaces R::
和 Rcpp::
拆分。它们被划分为:
- 标量 returns 单个值(例如
double
或 int
)
- 向量 returns 多个值(例如
NumericVector
或 IntegerVector
)
在这种情况下,您希望使用标量采样 space 而 而不是 矢量采样 space。
这是显而易见的,因为:
double a = dnorm(xs, 0, 1)[0]/dnorm(y(i), 0, 1)[0];
调用子集运算符[0]
获取向量中的唯一元素。
这个问题的第二部分是
提示的第四个参数缺失的部分
Line 12: no matching function for call to 'dnorm4'
如果您查看 dnorm
函数的 R 定义,您会看到:
dnorm(x, mean = 0, sd = 1, log = FALSE)
在这种情况下,您已经提供了除第四个参数以外的所有参数。
因此,您可能需要以下内容:
// [[Rcpp::export]]
NumericVector metropolis(int R, double b, double x0){
NumericVector y(R);
y(1) = x0; // C++ indices start at 0, you should change this!
for(int i=1; i<R; ++i){ // C++ indices start at 0!!!
y(i) = y(i-1);
double xs = y(i) + R::runif(-b, b);
double a = R::dnorm(xs, 0.0, 1.0, false)/R::dnorm(y(i), 0.0, 1.0, false);
NumericVector A(2);
A(0) = 1;
A(1) = a;
double random = R::runif(0.0, 1.0);
if(random <= min(A)){
y[i] = xs;
}
}
return y;
}
旁注:
C++ 索引从 0 而不是 1 开始。因此,您上面的向量有点问题,因为您在 [=22= 处填充 y
向量] 而不是 y(0)
。不过,我会把它作为练习留给你改正。
我正在为 N(0,1) 分布编写 Metropolis-Hastings 算法:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector metropolis(int R, double b, double x0){
NumericVector y(R);
y(1) = x0;
for(int i=1; i<R; ++i){
y(i) = y(i-1);
double xs = y(i)+runif(1, -b,b)[0];
double a = dnorm(xs, 0, 1)[0]/dnorm(y(i), 0, 1)[0];
NumericVector A(2);
A(0) = 1;
A(1) = a;
double random = runif(1)[0];
if(random <= min(A)){
y[i] = xs;
}
}
return y;
}
但每次我尝试编译该函数时,都会出现此错误:
Line 12: no matching function for call to 'dnorm4'
我尝试使用 dnorm 编写一个简单的函数,例如
NumericVector den(NumericVector y, double a, double b){
NumericVector x = dnorm(y,a,b);
return x;
}
并且有效。有人知道为什么我在 Metropolis 代码中有这种类型的错误吗? 是否有一些其他方法可以像在 R 中那样在 C++ 代码中使用密度函数?
在 Rcpp 中有两组采样器 - 标量和矢量 - 按名称spaces R::
和 Rcpp::
拆分。它们被划分为:
- 标量 returns 单个值(例如
double
或int
) - 向量 returns 多个值(例如
NumericVector
或IntegerVector
)
在这种情况下,您希望使用标量采样 space 而 而不是 矢量采样 space。
这是显而易见的,因为:
double a = dnorm(xs, 0, 1)[0]/dnorm(y(i), 0, 1)[0];
调用子集运算符[0]
获取向量中的唯一元素。
这个问题的第二部分是
提示的第四个参数缺失的部分Line 12: no matching function for call to 'dnorm4'
如果您查看 dnorm
函数的 R 定义,您会看到:
dnorm(x, mean = 0, sd = 1, log = FALSE)
在这种情况下,您已经提供了除第四个参数以外的所有参数。
因此,您可能需要以下内容:
// [[Rcpp::export]]
NumericVector metropolis(int R, double b, double x0){
NumericVector y(R);
y(1) = x0; // C++ indices start at 0, you should change this!
for(int i=1; i<R; ++i){ // C++ indices start at 0!!!
y(i) = y(i-1);
double xs = y(i) + R::runif(-b, b);
double a = R::dnorm(xs, 0.0, 1.0, false)/R::dnorm(y(i), 0.0, 1.0, false);
NumericVector A(2);
A(0) = 1;
A(1) = a;
double random = R::runif(0.0, 1.0);
if(random <= min(A)){
y[i] = xs;
}
}
return y;
}
旁注:
C++ 索引从 0 而不是 1 开始。因此,您上面的向量有点问题,因为您在 [=22= 处填充 y
向量] 而不是 y(0)
。不过,我会把它作为练习留给你改正。