############################################################################### # Package: sns # # # # Stochastic Newton Sampler (SNS)- implements the MH-MGT (Metropolis-Hastings # # with Multivariate Gaussian Tangents) algorithm described in the preprint: # # http://arxiv.org/abs/1308.0657 # # Draws samples from twice differentiable, log-concave pdf. # # # # Version: 1.0 # # # # Scientific Computing Group, Sentrana Inc. # ############################################################################### ############################################################################### # Core sampling function: draws samples from a multivariate pdf # Args: # init - starting point for the Markov chain # f - function, gradient, Hessian evaluator for the log-density. # Must a return a list with labels: # f - the log-probability density # g - gradient vector # h - Hessian matrix # rnd - Runs 1 iteration of Newton's method (non-stochastic) when FALSE # Runs Metropolis-Hastings for draw a sample when TRUE # NOTE: Set to FALSE only during burn-in # gfit - Gaussian fit at 'init'. If NULL, Gaussian fit at 'init' is computed # ... - Extra args all passed to evaluator whenever it's called # # Output: # The sample, drawn from the pdf, as a vector, with attributes: # accept - TRUE/FALSE, specifying whether the Metropolis move was accepted # ll - value of the function at the sampled point # gfit - Gaussian fit at the sampled point ############################################################################### sns <- function(init, fghEval, rnd=TRUE, gfit=NULL, ...) { f <- fghEval x <- init fitGaussian <- function(x, f, ...) { ret <- f(x,...) # Evaluate the function at 'x' Sigma <- solve(-ret$h) mu <- x + Sigma %*% ret$g return (list(mu=as.vector(mu), # Newton method solution Sigma=Sigma, # Inverse Hessian or Covariance matrix iSigma=-ret$h, # Inverse covariance or Hessian f=ret$f, # function value g=ret$g)) # gradient } # rnd: if FALSE, perform Newton's optimization (non-stochastic) # Fit Gaussian at x if (is.null(gfit)) gfit <- fitGaussian(x = x, f = f, ...) mu <- gfit$mu Sigma <- gfit$Sigma # Covariance iSigma <- gfit$iSigma # Inverse covariance K <- length(x); if (rnd) { # Draw sample from proposal distribution (Gaussian fit at x) x.prop <- as.vector(rmvnorm(n=1, mean=mu, sigma=Sigma)) } else { # Run (non-stochastic) Newton optimization rho <- 0.5; c <- 0.5; alphak <- 1; d <- mu - x; # use newton's direction as step search_x <- as.vector(mu); fk <- gfit$f; # Values at the current point gk <- gfit$g; fk1 <- f(search_x, ...)$f; # Function value at searching point ls_iter <- 1; # Linesearch by backtracking from full Newton step while (fk1 < fk + c*alphak*(t(gk)%*%d) && ls_iter < 20) { alphak <- alphak*rho; # if so, then go half way search_x <- x + alphak*d; fk1 <- f(search_x, ...)$f; ls_iter <- ls_iter + 1; } x.prop <- as.vector(search_x); } log.q.prop <- dmvnorm(as.vector(x.prop), mu, Sigma, log=TRUE) # fit Gaussian at x.prop gfit.prop <- fitGaussian(x=x.prop,f=f,...) mu.prop <- gfit.prop$mu Sigma.prop <- gfit.prop$Sigma iSigma.prop <- gfit.prop$iSigma # create MH acceptance ratio log.q <- dmvnorm(as.vector(x), mu.prop, Sigma.prop, log=TRUE) log.p <- gfit$f log.p.prop <- gfit.prop$f log.ratio <- (log.p.prop-log.p) + (log.q-log.q.prop) ratio <- min(1,exp(log.ratio)) # perform acceptance test if (ratio==1 || runif(1)