## Simple Gibbs Sampler Example ## Adapted from Darren Wilkinson's post at ## http://darrenjw.wordpress.com/2010/04/28/mcmc-programming-in-r-python-java-and-c/ ## ## Sanjog Misra and Dirk Eddelbuettel, June-July 2011 suppressMessages(library(Rcpp)) suppressMessages(library(inline)) suppressMessages(library(compiler)) suppressMessages(library(rbenchmark)) ## Actual joint density -- the code which follow implements ## a Gibbs sampler to draw from the following joint density f(x,y) fun <- function(x,y) { x*x * exp(-x*y*y - y*y + 2*y - 4*x) } ## Note that the full conditionals are propotional to ## f(x|y) = (x^2)*exp(-x*(4+y*y)) : a Gamma density kernel ## f(y|x) = exp(-0.5*2*(x+1)*(y^2 - 2*y/(x+1)) : Normal Kernel ## There is a small typo in Darrens code. ## The full conditional for the normal has the wrong variance ## It should be 1/sqrt(2*(x+1)) not 1/sqrt(1+x) ## This we can verify ... ## The actual conditional (say for x=3) can be computed as follows ## First - Construct the Unnormalized Conditional fy.unnorm <- function(y) fun(3,y) ## Then - Find the appropriate Normalizing Constant K <- integrate(fy.unnorm,-Inf,Inf) ## Finally - Construct Actual Conditional fy <- function(y) fy.unnorm(y)/K$val ## Now - The corresponding Normal should be fy.dnorm <- function(y) { x <- 3 dnorm(y,1/(1+x),sqrt(1/(2*(1+x)))) } ## and not ... fy.dnorm.wrong <- function(y) { x <- 3 dnorm(y,1/(1+x),sqrt(1/((1+x)))) } if (interactive()) { ## Graphical check ## Actual (gray thick line) curve(fy,-2,2,col='grey',lwd=5) ## Correct Normal conditional (blue dotted line) curve(fy.dnorm,-2,2,col='blue',add=T,lty=3) ## Wrong Normal (Red line) curve(fy.dnorm.wrong,-2,2,col='red',add=T) } ## Here is the actual Gibbs Sampler ## This is Darren Wilkinsons R code (with the corrected variance) ## But we are returning only his columns 2 and 3 as the 1:N sequence ## is never used below Rgibbs <- function(N,thin) { mat <- matrix(0,ncol=2,nrow=N) x <- 0 y <- 0 for (i in 1:N) { for (j in 1:thin) { x <- rgamma(1,3,y*y+4) y <- rnorm(1,1/(x+1),1/sqrt(2*(x+1))) } mat[i,] <- c(x,y) } mat } ## We can also try the R compiler on this R function RCgibbs <- cmpfun(Rgibbs) ## For example ## mat <- Rgibbs(10000,10); dim(mat) ## would give: [1] 10000 2 ## Now for the Rcpp version -- Notice how easy it is to code up! gibbscode <- ' using namespace Rcpp; // inline does that for us already // n and thin are SEXPs which the Rcpp::as function maps to C++ vars int N = as(n); int thn = as(thin); int i,j; NumericMatrix mat(N, 2); RNGScope scope; // Initialize Random number generator // The rest of the code follows the R version double x=0, y=0; for (i=0; i #include using namespace Rcpp; // just to be explicit ' gslgibbscode <- ' int N = as(ns); int thin = as(thns); int i, j; gsl_rng *r = gsl_rng_alloc(gsl_rng_mt19937); double x=0, y=0; NumericMatrix mat(N, 2); for (i=0; i