问题
I'm writing a Metropolis-Hastings algorithm for a N(0,1) distribution:
#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;
}
but every time I try to compile the function, this error occurs:
Line 12: no matching function for call to 'dnorm4'
I tried to write a trivial function using dnorm, like
NumericVector den(NumericVector y, double a, double b){
NumericVector x = dnorm(y,a,b);
return x;
}
and it works. Does someone know why I have this type of error in the Metropolis code? Are there some other ways to use density functions in the C++ code like in R?
回答1:
Within Rcpp there are two sets of samplers - scalar and vector - split by namespaces R::
and Rcpp::
. They are divided such that:
- Scalar returns a single value (e.g.
double
orint
) - Vector returns multiple values (e.g.
NumericVector
orIntegerVector
)
In this case, you want to be using the scalar sampling space and not the vector sampling space.
This is evident since:
double a = dnorm(xs, 0, 1)[0]/dnorm(y(i), 0, 1)[0];
Invokes the subset operator [0]
to obtain the only element in the vector.
The second part of this problem is the missing part of the fourth parameter as hinted by
Line 12: no matching function for call to 'dnorm4'
If you look at the R definition of the dnorm
function, you see:
dnorm(x, mean = 0, sd = 1, log = FALSE)
In this case, you've supplied all but the fourth parameter.
As a result, you'll probably want the following:
// [[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;
}
Side note:
C++ indices start at 0 not 1. As a result, your vector above is slightly problematic as you being by filling the y
vector at y(1)
and not y(0)
. I'll leave this as an exercise for you to correct though.
来源:https://stackoverflow.com/questions/41384303/rcpp-how-to-use-a-distribution-function-in-the-c-code