diff --git a/UserManual/src/_output.yml b/UserManual/src/_output.yml
index 5515f8b9d..64eaa0258 100644
--- a/UserManual/src/_output.yml
+++ b/UserManual/src/_output.yml
@@ -5,7 +5,7 @@ bookdown::gitbook:
before: |
-
NIMBLE User Manual, Version 1.4.2
+ NIMBLE User Manual, Version 1.4.3
NIMBLE Development Team
https://R-nimble.org
after: |
diff --git a/UserManual/src/chapter_MCMC.Rmd b/UserManual/src/chapter_MCMC.Rmd
index 60234d1e7..3092f1779 100644
--- a/UserManual/src/chapter_MCMC.Rmd
+++ b/UserManual/src/chapter_MCMC.Rmd
@@ -758,9 +758,8 @@ derived_name <- nimbleFunction(
##
## run fuction has one argument:
## timesRan, which is the number of times this method has executed during
- ## the present MCMC chain,
- ## including the present time. This can be used as an index for a matrix
- ## of results.
+ ## the present MCMC chain, including the present time. This can be used
+ ## as an index for a matrix of results.
##
},
methods = list(
@@ -768,7 +767,7 @@ derived_name <- nimbleFunction(
##
## REQUIRED `set_interval` method, which matches the definition below
## exactly.
- ## this method is necessary, to allow the default value of 'interval' to
+ ## This method is necessary, to allow the default value of 'interval' to
## match the thinning interval of the MCMC.
##
interval <<- newInterval
@@ -777,7 +776,7 @@ derived_name <- nimbleFunction(
before_chain = function(niter = double(), nburnin = double(),
thin = double(1), chain = double()) {
##
- ## (optional) `before_chain` method,
+ ## (optional) `before_chain` method:
## must have must have these arguments specifications:
## - niter (total number of *post-burnin* MCMC iterations)
## - nburnin (number of burnin iterations for this MCMC chain)
@@ -788,7 +787,7 @@ derived_name <- nimbleFunction(
},
after_chain = function() {
##
- ## (optional) `after_chain` method,
+ ## (optional) `after_chain` method:
## no arguments and no return value
##
},
@@ -808,7 +807,7 @@ derived_name <- nimbleFunction(
},
reset = function() {
##
- ## (optional) `reset` method
+ ## (optional) `reset` method:
## no arguments and no return value
##
}
diff --git a/UserManual/src/title.tex b/UserManual/src/title.tex
index 19690522a..6b0c7e5eb 100644
--- a/UserManual/src/title.tex
+++ b/UserManual/src/title.tex
@@ -4,7 +4,7 @@
\vspace{0.2in}
{\large NIMBLE Development Team}\\
\vspace{0.2in}
-{\large Version 1.4.2}\\
+{\large Version 1.4.3}\\
\vspace{3in}
\includegraphics[width=1.5in]{../nimble-icon.png}\\
{\large
diff --git a/packages/nimble/DESCRIPTION b/packages/nimble/DESCRIPTION
index 8c9d46484..73a27fc99 100644
--- a/packages/nimble/DESCRIPTION
+++ b/packages/nimble/DESCRIPTION
@@ -16,7 +16,7 @@ Description: A system for writing hierarchical statistical models largely
one can use 'NIMBLE' for writing arbitrary other kinds of model-generic
algorithms as well. A full User Manual is available at .
Version: 1.4.3
-Date: 2026-05-01
+Date: 2026-08-21
Maintainer: Christopher Paciorek
Authors@R: c(
person("Perry", "de Valpine", role = "aut"),
@@ -153,4 +153,4 @@ Collate:
registration.R
nimble-package.r
zzz.R
-RoxygenNote: 7.3.2
+RoxygenNote: 7.3.3
diff --git a/packages/nimble/INSTALL b/packages/nimble/INSTALL
index e04a7fe3f..cc9fe9d9a 100644
--- a/packages/nimble/INSTALL
+++ b/packages/nimble/INSTALL
@@ -1,9 +1,9 @@
You can install NIMBLE as an R package from CRAN in the usual way.
You can install from the source file using
- R CMD INSTALL nimble_1.4.2.tar.gz
+ R CMD INSTALL nimble_1.4.3.tar.gz
or
- install.packages("nimble_1.4.2.tar.gz", repos = NULL)
+ install.packages("nimble_1.4.3.tar.gz", repos = NULL)
You can also install the package directly from the NIMBLE repository
install.packages("nimble", repos = "https://r-nimble.org")
@@ -21,7 +21,7 @@ i.e. not Windows.
By default, we will use the Eigen distribution included with the package.
We can specify any or all of these with
- R CMD INSTALL nimble_1.4.2.tar.gz --configure-args="--enable-dylib=true --with-eigen=/Users/duncan/local"
+ R CMD INSTALL nimble_1.4.3.tar.gz --configure-args="--enable-dylib=true --with-eigen=/Users/duncan/local"
or
install.packages("nimble", configure.args = "--enable-dylib=true --with-eigen=/Users/duncan/local")
diff --git a/packages/nimble/R/BUGS_model.R b/packages/nimble/R/BUGS_model.R
index 2cf6e609b..27c9083cd 100644
--- a/packages/nimble/R/BUGS_model.R
+++ b/packages/nimble/R/BUGS_model.R
@@ -959,7 +959,9 @@ Details: The upward search for dependent nodes propagates through deterministic
if(self) { # The C++ call does *not* return self nodes
nodeFunIDs <- unique(modelDef$maps$vertexID_2_nodeID[ nodeIDs ])
parentIDs <- sort(c(parentIDs, nodeFunIDs))
- }
+ } else parentIDs <- setdiff(parentIDs, nodeIDs)
+
+
if(!includeRHSonly) parentIDs <- parentIDs[modelDef$maps$types[parentIDs] != 'RHSonly']
if(determOnly) parentIDs <- parentIDs[modelDef$maps$types[parentIDs] == 'determ']
if(stochOnly) parentIDs <- parentIDs[modelDef$maps$types[parentIDs] == 'stoch']
diff --git a/packages/nimble/R/cppDefs_ADtools.R b/packages/nimble/R/cppDefs_ADtools.R
index 1392efe5b..9b85e2994 100644
--- a/packages/nimble/R/cppDefs_ADtools.R
+++ b/packages/nimble/R/cppDefs_ADtools.R
@@ -2,6 +2,8 @@
#'
#' create an ADproxyModelClass object. For internal use.
#'
+#' @usage ADproxyModelClass(Rmodel)
+#'
#' @param Rmodel The name of an uncompiled model
#'
#' @author NIMBLE development team
diff --git a/packages/nimble/R/nimbleFunction_Rexecution.R b/packages/nimble/R/nimbleFunction_Rexecution.R
index c6e6958c9..ef83b3226 100644
--- a/packages/nimble/R/nimbleFunction_Rexecution.R
+++ b/packages/nimble/R/nimbleFunction_Rexecution.R
@@ -107,6 +107,8 @@ nimSeq <- function(from, to, by, length.out) { ## this creates default arguments
#'
#' @name setupOutputs
#'
+#' @usage setupOutputs(...)
+#'
#' @param ... An arbitrary set of names
#'
#' @details
diff --git a/packages/nimble/R/nimbleList_core.R b/packages/nimble/R/nimbleList_core.R
index 692afcea4..5fb7c30cc 100644
--- a/packages/nimble/R/nimbleList_core.R
+++ b/packages/nimble/R/nimbleList_core.R
@@ -27,6 +27,8 @@ nimbleListBase <- setRefClass(Class = 'nimbleListBase',
#'
#' Create a nimbleType object, with information on the name, type, and dimension of an object to be placed in a \code{\link{nimbleList}}.
#'
+#' @usage nimbleType(name, type, dim = NA)
+#'
#' @param name The name of the object, given as a character string.
#' @param type The type of the object, given as a character string.
#' @param dim The dimension of the object, given as an integer. This can be left blank if the object is a nimbleList.
diff --git a/packages/nimble/R/setupMargNodes.R b/packages/nimble/R/setupMargNodes.R
index ecb92c536..38872fc7e 100644
--- a/packages/nimble/R/setupMargNodes.R
+++ b/packages/nimble/R/setupMargNodes.R
@@ -91,15 +91,19 @@
#' \code{calcNodes}. Such deterministic nodes will be included in
#' calculations automatically when needed.
#'
-#' If \code{randomEffectsNodes} is missing, the default is a bit complicated: it
-#' includes all latent nodes that are descendants (or "downstream") of
-#' \code{paramNodes} (if provided) and are either (i) ancestors (or
-#' "upstream") of data nodes (if \code{calcNodes} is missing), or (ii)
-#' ancestors or elements of \code{calcNodes} (if \code{calcNodes} and
-#' \code{paramNodes} are provided), or (iii) elements of \code{calcNodes} (if
-#' \code{calcNodes} is provided but \code{paramNodes} is missing). In all
-#' cases, discrete nodes (with warning if \code{check=TRUE}), posterior
-#' predictive nodes and \code{paramNodes} are excluded.
+#' If \code{randomEffectsNodes} is missing, the default is a bit complicated.
+#' It starts by considering all latent nodes as potential \code{randomEffectsNodes}.
+#' If \code{paramNodes} is provided, only latent nodes that are downstream of
+#' \code{paramNodes} are included in the potential nodes.
+#' Then the set of potential nodes is filtered to
+#' include only nodes that satisfy one of the following conditions
+#' (only one of which will be applicable): (i) parents of data nodes
+#' (applies only if calcNodes is missing), (ii) parents or elements of
+#' \code{calcNodes} (applies only if \code{calcNodes} and \code{paramNodes}
+#' are both provided), (iii) elements of calcNodes (applies if \code{calcNodes}
+#' is provided but \code{paramNodes} is missing). In all
+#' cases, discrete nodes (with warning if \code{check=TRUE}), posterior
+#' predictive nodes and \code{paramNodes} are excluded.
#'
#' \code{randomEffectsNodes} should only include stochastic nodes.
#'
@@ -234,8 +238,6 @@ setupMargNodes <- function(model, paramNodes, randomEffectsNodes, calcNodes,
} else {
nodesToFindParentsFrom <- randomEffectsNodes
paramNodes <- model$getParents(nodesToFindParentsFrom, self=FALSE, stochOnly=TRUE)
- # self=FALSE doesn't omit if one RE node is a parent of another, so we have to do the next step
- paramNodes <- setdiff(paramNodes, nodesToFindParentsFrom)
}
if(paramsHandled) {
if(calcProvided) paramNodes <- setdiff(paramNodes, calcNodes)
@@ -283,21 +285,18 @@ setupMargNodes <- function(model, paramNodes, randomEffectsNodes, calcNodes,
tempDataNodesDefault <- model$getNodeNames(dataOnly = TRUE)
if(paramsHandled)
tempDataNodesDefault <- setdiff(tempDataNodesDefault, paramNodes)
- tempDataNodesDefaultParents <- model$getParents(tempDataNodesDefault, upstream = TRUE, stochOnly = TRUE)
- # See comment above about why this is necessary:
- tempDataNodesDefaultParents <- setdiff(tempDataNodesDefaultParents, tempDataNodesDefault)
+ tempDataNodesDefaultParents <- model$getParents(tempDataNodesDefault, upstream = TRUE, stochOnly = TRUE,
+ self = FALSE)
reNodesDefault <- intersect(reNodesDefault, tempDataNodesDefaultParents)
} else {
# Update reNodesDefault to exclude nodes that lack downstream connection to a calcNode
if(paramsHandled) { # This means reProvided OR paramsProvided. Including parents allows checking
# of potentially missing REs.
reNodesDefault <- intersect(reNodesDefault,
- model$getParents(calcNodes, upstream=TRUE, stochOnly = TRUE))
+ model$getParents(calcNodes, upstream=TRUE, stochOnly = TRUE, self = TRUE))
} else { # This means !paramsHandled and hence !reProvided AND !paramsProvided
reNodesDefault <- intersect(reNodesDefault,
calcNodes)
- reNodesDefault <- intersect(reNodesDefault,
- model$getParents(calcNodes, upstream=TRUE, stochOnly = TRUE))
}
}
}
@@ -306,8 +305,6 @@ setupMargNodes <- function(model, paramNodes, randomEffectsNodes, calcNodes,
# and are now ready to create default paramNodes
if(!paramsHandled) {
paramNodes <- model$getParents(reNodesDefault, self=FALSE, stochOnly=TRUE)
- # See comment above about why this is necessary:
- paramNodes <- setdiff(paramNodes, reNodesDefault)
if(calcOtherProvided) paramNodes <- setdiff(paramNodes, calcNodesOther)
}
@@ -414,8 +411,6 @@ setupMargNodes <- function(model, paramNodes, randomEffectsNodes, calcNodes,
if(!paramProvided) {
possibleNewParamNodes <- model$getParents(calcNodes, self=FALSE, stochOnly=TRUE, includeData=FALSE)
# includeData=FALSE as data nodes cannot be parameters
- # self=FALSE doesn't omit if one node is a parent of another, so we have to do the next step
- possibleNewParamNodes <- setdiff(possibleNewParamNodes, calcNodesDefault)
paramNodes <- unique(c(paramNodes, possibleNewParamNodes))
}
diff --git a/packages/nimble/man/ADproxyModelClass-class.Rd b/packages/nimble/man/ADproxyModelClass-class.Rd
index 6309bcea4..03d37bb11 100644
--- a/packages/nimble/man/ADproxyModelClass-class.Rd
+++ b/packages/nimble/man/ADproxyModelClass-class.Rd
@@ -5,6 +5,9 @@
\alias{ADproxyModelClass-class}
\alias{ADproxyModelClass}
\title{create an ADproxyModelClass object}
+\usage{
+ADproxyModelClass(Rmodel)
+}
\arguments{
\item{Rmodel}{The name of an uncompiled model}
}
diff --git a/packages/nimble/man/nimbleType-class.Rd b/packages/nimble/man/nimbleType-class.Rd
index f9cf25943..242e3d16c 100644
--- a/packages/nimble/man/nimbleType-class.Rd
+++ b/packages/nimble/man/nimbleType-class.Rd
@@ -5,6 +5,9 @@
\alias{nimbleType-class}
\alias{nimbleType}
\title{create a nimbleType object}
+\usage{
+nimbleType(name, type, dim = NA)
+}
\arguments{
\item{name}{The name of the object, given as a character string.}
diff --git a/packages/nimble/man/samplers.Rd b/packages/nimble/man/samplers.Rd
index 9ffd1b96c..26e21222d 100644
--- a/packages/nimble/man/samplers.Rd
+++ b/packages/nimble/man/samplers.Rd
@@ -570,20 +570,17 @@ The CRP_concentration sampler is designed for Bayesian nonparametric mixture mod
\section{prior_samples sampler}{
-The prior_samples sampler uses a provided set of numeric values (\code{samples}) to define the prior distribution of one or more model nodes. One every MCMC iteration, the prior_samples sampler takes value(s) from the numeric values provided, and stores these value(s) into the target model node(s). This allows one to define the prior distribution of model parameters empirically, using a set of numeric \code{samples}, presumably obtained previously using MCMC. The \code{target} node may be either a single scalar node (scalar case), or a collection of model nodes.
+The prior_samples sampler uses a provided set of numeric values (\code{samples}) to define the prior distribution of one or more model nodes. Once every MCMC iteration, the prior_samples sampler randomly selects new value(s) from the numeric values provided, and probabilistically accepts these as the new values for the specific target node(s) using a standard Metropolis-Hastings accept/reject step. This allows one to define the prior distribution of model parameters empirically, using a set of numeric \code{samples}, presumably obtained previously using MCMC.
-The prior_samples sampler provides two options for selection of the value to use on each MCMC iteration. The default behaviour is to take sequential values from the \code{samples} vector (scalar case), or in the case of multiple dimensions, sequential rows of the \code{samples} matrix are used. The alternative behaviour, by setting the control argument \code{randomDraws = TRUE}, will instead use random draws from the \code{samples} vector (scalar case), or randomly selected rows of the \code{samples} matrix in the multidimensional case.
-
-If the default of sequential selection of values is used, and the number of MCMC iterations exceeds the length of the \code{samples} vector (scalar case) or the number of rows of the \code{samples} matrix, then \code{samples} will be recycled as necessary for the number of MCMC iterations. A message to this effect is also printed at the beginning of the MCMC chain.
+The \code{target} node may be either a single scalar node (scalar case), or a collection of model nodes (multidimensional case). In the scalar case, a propsed value is randomely selected from the \code{samples} vector. In the multidimensional case, a randomly selected rows of the \code{samples} matrix is used as the proposed values.
Logically, prior_samples samplers might want to operate first, in advance of other samplers, on every MCMC iteration. By default, at the time of MCMC building, all prior_samples samplers are re-ordered to appear first in the list of MCMC samplers. This behavior can be subverted, however, by setting \code{nimbleOptions(MCMCorderPriorSamplesSamplersFirst = FALSE)}.
-The prior_samples sampler can be assigned to non-stochastic model nodes (nodes which are not assigned a prior distribution in the model). In fact, it is recommended that nodes being assigned a prior_samples are not provided with a prior distribution in the model, and rather, that these nodes only appear on the right-hand-side of model declaration lines. In such case that a prior_samples sampler is assigned to a nodes with a prior distribution, the prior distribution will be overridden by the sample values provided to the sampler; however, the node will still be a stochastic node for other purposes, and will contribute to the model joint-density (using the sample values provided relative to the prior distribution), will have an MCMC sampler assigned to it by default, and also may introduce potential for confusion. In this case, a message is issued at the time of MCMC building.
+The prior_samples sampler can be assigned to non-stochastic model nodes (nodes which are not assigned a prior distribution in the model). In fact, it is recommended that nodes being assigned a prior_samples are not provided with a prior distribution in the model, and rather, that these nodes only appear on the right-hand-side of model declaration lines. In such case that a prior_samples sampler is assigned to a nodes with a prior distribution, the prior distribution will be overridden by the \code{samples} provided to the sampler; however, the node will still be a stochastic node for other purposes, and will contribute to the model joint-density (using the current values relative to the prior distribution), will have an MCMC sampler assigned to it by default, and also may introduce potential for confusion. In this case, a message is issued at the time of MCMC building.
The prior_samples sampler accepts the following control list elements:
\itemize{
-\item \code{samples}. A numeric vector or matrix. When the \code{target} node is a single scalar-valued node, \code{samples} should be a numeric vector. When the \code{target} node specifies d > 2 model dimensions, \code{samples} should be a matrix containing d columns. The \code{samples} control argument is required.
-\item \code{randomDraws}. A logical argument, specifying whether to use a random draw from \code{samples} on each iteration. If \code{samples} is a matrix, then a randomly-selected row of the \code{samples} matrix is used. When \code{FALSE}, sequential values (or sequential matrix rows) are used (default = \code{FALSE}).
+\item \code{samples}. A numeric vector or matrix. When the \code{target} node is a single scalar-valued node, \code{samples} should be a numeric vector. When the \code{target} node specifies more \code{d} > 2 dimensions, \code{samples} should be a matrix containing \code{d} columns. The \code{samples} control argument is required.
}
}
diff --git a/packages/nimble/man/setupMargNodes.Rd b/packages/nimble/man/setupMargNodes.Rd
index 7fc1e1683..cab6d7f45 100644
--- a/packages/nimble/man/setupMargNodes.Rd
+++ b/packages/nimble/man/setupMargNodes.Rd
@@ -134,15 +134,19 @@ For purposes of \code{buildLaplace}, \code{paramNodes} does not need to (but
\code{calcNodes}. Such deterministic nodes will be included in
calculations automatically when needed.
-If \code{randomEffectsNodes} is missing, the default is a bit complicated: it
- includes all latent nodes that are descendants (or "downstream") of
- \code{paramNodes} (if provided) and are either (i) ancestors (or
- "upstream") of data nodes (if \code{calcNodes} is missing), or (ii)
- ancestors or elements of \code{calcNodes} (if \code{calcNodes} and
- \code{paramNodes} are provided), or (iii) elements of \code{calcNodes} (if
- \code{calcNodes} is provided but \code{paramNodes} is missing). In all
- cases, discrete nodes (with warning if \code{check=TRUE}), posterior
- predictive nodes and \code{paramNodes} are excluded.
+ If \code{randomEffectsNodes} is missing, the default is a bit complicated.
+ It starts by considering all latent nodes as potential \code{randomEffectsNodes}.
+ If \code{paramNodes} is provided, only latent nodes that are downstream of
+ \code{paramNodes} are included in the potential nodes.
+ Then the set of potential nodes is filtered to
+ include only nodes that satisfy one of the following conditions
+ (only one of which will be applicable): (i) parents of data nodes
+ (applies only if calcNodes is missing), (ii) parents or elements of
+ \code{calcNodes} (applies only if \code{calcNodes} and \code{paramNodes}
+ are both provided), (iii) elements of calcNodes (applies if \code{calcNodes}
+ is provided but \code{paramNodes} is missing). In all
+ cases, discrete nodes (with warning if \code{check=TRUE}), posterior
+ predictive nodes and \code{paramNodes} are excluded.
\code{randomEffectsNodes} should only include stochastic nodes.
diff --git a/packages/nimble/man/setupOutputs.Rd b/packages/nimble/man/setupOutputs.Rd
index 9870a9b2d..5b4853508 100644
--- a/packages/nimble/man/setupOutputs.Rd
+++ b/packages/nimble/man/setupOutputs.Rd
@@ -3,6 +3,9 @@
\name{setupOutputs}
\alias{setupOutputs}
\title{Explicitly declare objects created in setup code to be preserved and compiled as member data}
+\usage{
+setupOutputs(...)
+}
\arguments{
\item{...}{An arbitrary set of names}
}
diff --git a/packages/nimble/tests/testthat/test-getDependencies.R b/packages/nimble/tests/testthat/test-getDependencies.R
index 028a5c545..acd75a7bf 100644
--- a/packages/nimble/tests/testthat/test-getDependencies.R
+++ b/packages/nimble/tests/testthat/test-getDependencies.R
@@ -154,12 +154,12 @@ test_that("getParents works in model with no criss-crossing dependencies", {
expect_identical(m1$getParents("f1"), c("a1", "a2", "c2", "c4", "c3"))
expect_identical(m1$getParents("f1", immediateOnly = TRUE), c("c4", "c3"))
- expect_identical(m1$getParents(c("f1", "g1"), stochOnly = TRUE), c("a1", "a2", "f1"))
- expect_identical(m1$getParents(c("f1", "g1"), immediateOnly = TRUE), c("c4", "c3", "f1"))
- expect_identical(m1$getParents(c("g1", "f1"), stochOnly = TRUE), c("a1", "a2", "f1"))
+ expect_identical(m1$getParents(c("f1", "g1"), stochOnly = TRUE), c("a1", "a2"))
+ expect_identical(m1$getParents(c("f1", "g1"), immediateOnly = TRUE), c("c4", "c3"))
+ expect_identical(m1$getParents(c("g1", "f1"), stochOnly = TRUE), c("a1", "a2"))
expect_identical(m1$getParents(c("f1", "g1"), stochOnly = TRUE, self = TRUE), c("a1", "a2", "f1", "g1"))
- expect_identical(m1$getParents(c("c3", "c2", "e1"), stochOnly = FALSE), c("a1", "c2", "c3"))
- expect_identical(m1$getParents(c("c3", "c2", "e1"), immediateOnly = TRUE, stochOnly = FALSE), c("a1", "c2", "c3"))
+ expect_identical(m1$getParents(c("c3", "c2", "e1"), stochOnly = FALSE), c("a1"))
+ expect_identical(m1$getParents(c("c3", "c2", "e1"), immediateOnly = TRUE, stochOnly = FALSE), c("a1"))
expect_identical(m1$getParents("h1", includeRHSonly = TRUE, stochOnly = FALSE), c("lho"))
})
diff --git a/packages/nimble/tests/testthat/test-setupMargNodes.R b/packages/nimble/tests/testthat/test-setupMargNodes.R
index 9eea48df8..e844aa369 100644
--- a/packages/nimble/tests/testthat/test-setupMargNodes.R
+++ b/packages/nimble/tests/testthat/test-setupMargNodes.R
@@ -436,7 +436,7 @@ test_that("setupMargNodes finds correct randomEffectsNodes based on calcNodes in
})
m <- nimbleModel(code, data = list(y = c(1, 2)))
SMN <- setupMargNodes(m, calcNodes = c("r", "s"))
- expect_identical(SMN$randomEffectsNodes, c("r[1]","r[2]"))
+ expect_identical(SMN$randomEffectsNodes, c("r[1]","r[2]","s[1]","s[2]"))
expect_identical(SMN$paramNodes, c("p[1]","p[2]"))
})