···3939#' @param epsilon density threshold
4040#' @param h lattice size
4141#' @param M maximum number of doublings
4242-#' @returns One NURS step from theta.
4242+#' @returns next draw
4343NURS_step <- function(logpdf, theta, epsilon, h, M) {
4444 d <- length(theta)
4545 # hit
···5757 theta + s * rho else theta
58585959 log_eps_h <- log(epsilon) + log(h)
6060- orbit_points <- list(theta0)
6161- log_vals <- logpdf(theta0)
6060+ logW <- logpdf(theta0)
6161+ theta_tilde <- theta0
62626363 # bookkeeping to get orbit ends
6464 left <- right <- 1
6565+ left_point <- right_point <- theta0
6666+ left_val <- right_val <- logW
65676668 # Orbit selection procedure
6769 B <- sample(c(FALSE, TRUE), M, replace = TRUE)
···7072 n_ext <- 2^(k - 1)
7173 orbit_ext <- lapply(
7274 seq_len(n_ext),
7373- \(i)
7474- (if (B_k) orbit_points[[right]] else orbit_points[[left]]) +
7575- (2 * B_k - 1) * i * h * rho
7575+ \(i) (if (B_k) right_point else left_point) + i * (2 * B_k - 1) * h * rho
7676 )
7777 log_ext <- sapply(orbit_ext, logpdf)
78787979+ # Recursive sub-stopping criterion
7980 if (NURS_sub_stop(log_ext, log_eps_h)) break
80818282+ for (i in seq_len(n_ext)) {
8383+ theta_i <- orbit_ext[[i]]
8484+ log_i <- log_ext[i]
8585+ logW_new <- log_sum_exp(c(logW, log_i))
8686+ if (runif(1) < exp(log_i - logW_new)) theta_tilde <- theta_i
8787+ logW <- logW_new
8888+ }
8989+8190 if (B_k) {
8282- orbit_points <- c(orbit_points, orbit_ext)
8383- log_vals <- c(log_vals, log_ext)
9191+ right_point <- orbit_ext[[n_ext]]
9292+ right_val <- log_ext[n_ext]
8493 } else {
8585- orbit_points <- c(orbit_ext, orbit_points)
8686- log_vals <- c(log_ext, log_vals)
8787- left <- 1
9494+ left_point <- orbit_ext[[n_ext]]
9595+ left_val <- log_ext[n_ext]
8896 }
8989- right <- right + n_ext
90979191- if (NURS_stop(log_vals, log_eps_h)) break
9898+ # No-underrun stopping criterion
9999+ if (max(left_val, right_val) <= log_eps_h + logW) break
92100 }
931019494- orbit_points[[sample(
9595- length(log_vals),
9696- 1,
9797- prob = exp(log_vals - log_sum_exp(log_vals))
9898- )]]
102102+ theta_tilde
99103}
100104101105#' NURS draws
···103107#' @param logpdf log (non-normalized) target density
104108#' @param theta_init initial state
105109#' @param n number of draws
106106-#' @param epsilon density threshold
107107-#' @param h lattice size
110110+#' @param epsilon non-negative density threshold
111111+#' @param h positive lattice size
108112#' @param M maximum number of doublings
113113+#' @returns a sequence of draws
114114+#'
109115#' @export
110116#' @source <https://arxiv.org/abs/2501.18548v2>
111117NURS <- function(logpdf, theta_init, n, epsilon, h, M) {
118118+ stopifnot(epsilon >= 0, h > 0)
112119 d <- length(theta_init)
113120 draws <- matrix(NA, n, d)
114121 draws[1, ] <- theta_init
+2-1
README.Rmd
···1818<!-- badges: start -->
1919<!-- badges: end -->
20202121-A Base R, simple implementation of the No-Underrun Sampler. This implementation aims to mostly directly implement the algorithm as described by the paper, with at most small changes for code aesthetics and performance.
2121+A Base R, simple implementation of the No-Underrun Sampler. This implementation aims to mostly directly implement the algorithm as described by the paper, with at most small changes for code aesthetics and performance. This version uses the memory saving technique described in section 2.2.
22222323## Installation
2424···4040 y <- theta[1]
4141 dnorm(y, 0, 3, log = TRUE) + sum(dnorm(theta[-1], 0, exp(y / 2), log = TRUE))
4242}
4343+4344samples <- NURS(
4445 logpdf_funnel,
4546 theta_init = rep(0, 15),
+3-1
README.md
···1010A Base R, simple implementation of the No-Underrun Sampler. This
1111implementation aims to mostly directly implement the algorithm as
1212described by the paper, with at most small changes for code aesthetics
1313-and performance.
1313+and performance. This version uses the memory saving technique described
1414+in section 2.2.
14151516## Installation
1617···3334 y <- theta[1]
3435 dnorm(y, 0, 3, log = TRUE) + sum(dnorm(theta[-1], 0, exp(y / 2), log = TRUE))
3536}
3737+3638samples <- NURS(
3739 logpdf_funnel,
3840 theta_init = rep(0, 15),
+5-2
man/NURS.Rd
···16161717\item{n}{number of draws}
18181919-\item{epsilon}{density threshold}
1919+\item{epsilon}{non-negative density threshold}
20202121-\item{h}{lattice size}
2121+\item{h}{positive lattice size}
22222323\item{M}{maximum number of doublings}
2424+}
2525+\value{
2626+a sequence of draws
2427}
2528\description{
2629NURS draws
+1-1
man/NURS_step.Rd
···1818\item{M}{maximum number of doublings}
1919}
2020\value{
2121-One NURS step from theta.
2121+next draw
2222}
2323\description{
2424Single NURS step