From 4992dfc3bb61dfead30a283a9d07ae5100484f95 Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Thu, 11 Jun 2026 07:57:50 -0700 Subject: [PATCH 1/2] Export nimbleCode. --- nimbleModel/NAMESPACE | 1 + 1 file changed, 1 insertion(+) diff --git a/nimbleModel/NAMESPACE b/nimbleModel/NAMESPACE index a7cc763..34fa9d2 100644 --- a/nimbleModel/NAMESPACE +++ b/nimbleModel/NAMESPACE @@ -70,5 +70,6 @@ export(messageIfVerbose) export(calc_dmnormAltParams) export(calc_dwishAltParams) +export(nimbleCode) export(nimbleModel) export(makeInstrList) From 4b2d8cc3696364200dbbd56cdee9489202af9937 Mon Sep 17 00:00:00 2001 From: Christopher Paciorek Date: Thu, 11 Jun 2026 08:52:56 -0700 Subject: [PATCH 2/2] Add classic node handling as chars for getNodes, getParents, getDeps. --- nimbleModel/NAMESPACE | 3 +++ nimbleModel/R/model.R | 17 ++++++++++++++--- nimbleModel/R/modelBaseClass.R | 22 ++++++++++++++++------ nimbleModel/R/modelDef.R | 16 ++++++++++++---- nimbleModel/R/options.R | 2 ++ nimbleModel/R/processModelGraph.R | 14 ++++++++++++-- 6 files changed, 59 insertions(+), 15 deletions(-) diff --git a/nimbleModel/NAMESPACE b/nimbleModel/NAMESPACE index 34fa9d2..72e79d3 100644 --- a/nimbleModel/NAMESPACE +++ b/nimbleModel/NAMESPACE @@ -73,3 +73,6 @@ export(calc_dwishAltParams) export(nimbleCode) export(nimbleModel) export(makeInstrList) + +export(setNimbleModelOption) +export(getNimbleModelOption) diff --git a/nimbleModel/R/model.R b/nimbleModel/R/model.R index efac3f5..af98be5 100644 --- a/nimbleModel/R/model.R +++ b/nimbleModel/R/model.R @@ -327,7 +327,10 @@ getNodes <- function(model, nodes = NULL, includeData = TRUE, dataOnly = FALSE, includePredictive = TRUE, predictiveOnly = FALSE, includeRHSonly = FALSE, - topOnly = FALSE, latentOnly = FALSE, endOnly = FALSE) { + topOnly = FALSE, latentOnly = FALSE, endOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { # `nodes` may contain one or more varRanges or varNames. if (topOnly + latentOnly + endOnly > 1) { stop("only one of `topOnly`, `latentOnly`, `endOnly` can be `TRUE`.") @@ -393,6 +396,14 @@ getNodes <- function(model, nodes = NULL, if (!length(result)) { return(NULL) } - - return(removeDuplicateVarRanges(result)) + if (nodesAsChars) { + if (returnScalarComponents) { + result <- sapply(result, \(x) x$toVarRange()$toVarChars(expandScalars = TRUE)) + } else result <- sapply(result, \(x) x$toNodeChars()) + return(unlist(result)) + } else { + if (returnScalarComponents) # TODO: put into new messaging system + warning("one must request result as characters via `nodesAsChars` or `classicNimble` in order to use `returnScalarComponents`") + } + return(result) } diff --git a/nimbleModel/R/modelBaseClass.R b/nimbleModel/R/modelBaseClass.R index f6e216d..c83e0f1 100644 --- a/nimbleModel/R/modelBaseClass.R +++ b/nimbleModel/R/modelBaseClass.R @@ -307,11 +307,19 @@ modelBase_nClass <- nClass( return(expr) } }, - getDependencies = function(nodes, self = TRUE, downstream = FALSE, immediateOnly = FALSE) { - nimbleModel::getDependencies(modelDef, nodes, self, downstream, immediateOnly) + getDependencies = function(nodes, self = TRUE, downstream = FALSE, immediateOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { + nimbleModel::getDependencies(modelDef, nodes, self, downstream, immediateOnly, + nodesAsChars, returnScalarComponents) }, - getParents = function(nodes, self = TRUE, upstream = FALSE, immediateOnly = FALSE) { - nimbleModel::getParents(modelDef, nodes, self, upstream, immediateOnly) + getParents = function(nodes, self = TRUE, upstream = FALSE, immediateOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { + nimbleModel::getParents(modelDef, nodes, self, upstream, immediateOnly, + nodesAsChars, returnScalarComponents) }, # TODO: not working because `nimbleModel::getNodes` needs the model not just modelDef. # Once we integrate modelClass with modelBase_nClass, we should be able to pass `self`. @@ -319,11 +327,13 @@ modelBase_nClass <- nClass( includeData = TRUE, dataOnly = FALSE, includePredictive = TRUE, predictiveOnly = FALSE, includeRHSonly = FALSE, - topOnly = FALSE, latentOnly = FALSE, endOnly = FALSE) { + topOnly = FALSE, latentOnly = FALSE, endOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE) { nimbleModel::getNodes( self, nodes, stochOnly, determOnly, includeData, dataOnly, includePredictive, predictiveOnly, includeRHSonly, - topOnly, latentOnly, endOnly + topOnly, latentOnly, endOnly, nodesAsChars, returnScalarComponents ) }, calc_op = function(instr, fn, fn_cpp) { diff --git a/nimbleModel/R/modelDef.R b/nimbleModel/R/modelDef.R index 370c5eb..5cb38d7 100644 --- a/nimbleModel/R/modelDef.R +++ b/nimbleModel/R/modelDef.R @@ -999,21 +999,29 @@ modelDefClass <- R6Class( getDependencies <- function(modelDef, nodes, self = TRUE, - downstream = FALSE, immediateOnly = FALSE) { + downstream = FALSE, immediateOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { traverseGraph(modelDef$downstreamRules, modelDef$declRules, nodes = nodes, down = TRUE, self = self, - follow = downstream, immediateOnly = immediateOnly + follow = downstream, immediateOnly = immediateOnly, + nodesAsChars = nodesAsChars, returnScalarComponents = returnScalarComponents ) } getParents <- function(modelDef, nodes, self = FALSE, - upstream = FALSE, immediateOnly = FALSE) { + upstream = FALSE, immediateOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { traverseGraph(modelDef$upstreamRules, modelDef$declRules, nodes = nodes, down = FALSE, self = self, - follow = upstream, immediateOnly = immediateOnly + follow = upstream, immediateOnly = immediateOnly, + nodesAsChars = nodesAsChars, returnScalarComponents = returnScalarComponents ) } diff --git a/nimbleModel/R/options.R b/nimbleModel/R/options.R index 37e4037..41e47ad 100644 --- a/nimbleModel/R/options.R +++ b/nimbleModel/R/options.R @@ -8,11 +8,13 @@ # but this has .GlobalEnv as a parent. processBackwardsModelIndexRanges = TRUE, disallowMultivariateArgumentExpressions = TRUE, + nodesAsChars = FALSE, verbose = TRUE ) ) # sets a single option +#' @export setNimbleModelOption <- function(name, value) { assign(name, value, envir = .nimbleModelOptions) invisible(value) diff --git a/nimbleModel/R/processModelGraph.R b/nimbleModel/R/processModelGraph.R index 12325e6..e7d0d0c 100644 --- a/nimbleModel/R/processModelGraph.R +++ b/nimbleModel/R/processModelGraph.R @@ -242,7 +242,10 @@ setSortIDs <- function(calcRules) { # pass result through `getNodes`. traverseGraph <- function(streamRules, declRules, nodes, down, self = TRUE, - follow = FALSE, immediateOnly = FALSE) { + follow = FALSE, immediateOnly = FALSE, + nodesAsChars = getNimbleModelOption('nodesAsChars'), + returnScalarComponents = FALSE + ) { if (inherits(nodes, "varRangeClass")) nodes <- list(nodes) # We use `lapply` on 'nodes' later. results <- traverseGraphRecurse(streamRules, nodes, down, follow, immediateOnly) @@ -321,7 +324,14 @@ traverseGraph <- function(streamRules, declRules, if (!length(results)) { return(NULL) } - return(removeDuplicateVarRanges(results)) + results <- removeDuplicateVarRanges(results) + if (nodesAsChars) { + return(unlist(sapply(results, \(x) x$toVarChars(expandScalars = returnScalarComponents)))) + } else { + if (returnScalarComponents) # TODO: put into new messaging system + warning("one must request result as characters via `nodesAsChars` or `classicNimble` in order to use `returnScalarComponents`") + } + return(results) } traverseGraphRecurse <- function(rules, nodes, down, follow = FALSE, immediateOnly = FALSE, firstPass = TRUE) {