Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3f062f4
changes to support work on nimble2
perrydv Jun 22, 2026
2a6c093
Initial wiring of values() with copier and multiCopier works
perrydv Jul 11, 2026
141def1
support values() in nimble2 via multiCopier and (uncompiled) values()
perrydv Jul 13, 2026
8371b08
modelValues generated classes work
perrydv Jul 17, 2026
d4e63d9
clean up test-modelValues.R
perrydv Jul 17, 2026
00f0df9
run styler::style on recently changed files
perrydv Jul 17, 2026
a12bd9d
cleaned up modelValues, set up nClassBuilder, add tests
perrydv Jul 24, 2026
30077eb
add defaultSizes and varInfo to modelValues
perrydv Jul 28, 2026
59cff2b
put scoping on nList uses for regularity and safety
perrydv Aug 5, 2026
b793372
fix model initialize routine to handle returned base class pointers a…
perrydv Aug 5, 2026
0ff1129
fix modelValues base class initialize and cleanup
perrydv Aug 6, 2026
6dd28e9
modelValues works with generic bracket and length getters and setters…
perrydv Aug 6, 2026
732801f
Make dot_sizeList and dot_current_nRow be "hidden"
perrydv Aug 11, 2026
906a59e
Add multiCopier variant for modelValues. Update both variants to rese…
perrydv Aug 14, 2026
3a99b0f
basic getParam works
perrydv Aug 19, 2026
54f108e
getParam and getBound work, compiled and uncompiled, tested only for …
perrydv Aug 25, 2026
5459387
catching up on styler formatting
perrydv Aug 26, 2026
5c12769
mostly cleanup. Add .onLoad. Add some opDefs.
perrydv Oct 1, 2026
46e5b6b
getParamID added. with getParam and getBound these work from strings.
perrydv Oct 2, 2026
67fda06
tools for getParam and getBound, including new getParamID methods
perrydv Oct 5, 2026
b84482f
update predefined classes to include an nc_type_key
perrydv Oct 6, 2026
675a637
Merge branch 'master' into support-nimble2-resolve-conflicts
perrydv Oct 8, 2026
a190b98
add package digest to test setup
perrydv Oct 8, 2026
c073ff5
updates fixing disconnects from long diverged branch merging
perrydv Oct 8, 2026
e6972ce
Ensure replacements (e.g. idx for i) are used for altParamExprs
perrydv Oct 12, 2026
2289b34
Fix tests. Shorten some predefined names. Pick up updates to nCompiler.
perrydv Oct 12, 2026
57ee4f0
replace expect_identical with expect_equal in some modelValues tests
perrydv Oct 13, 2026
61b7faa
remove old predefined folders that have been replaced
perrydv Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
run: |
install.packages(c('testthat', 'remotes'))
install.packages('R6')
install.packages('digest')
install.packages('nimble') # For now, we use `nimble` for stuff in `miscFunctions.R`.
install.packages('inline') # For now, seemingly need for nCompiler.
remotes::install_github("https://github.com/nimble-dev/nCompiler", subdir="nCompiler")
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ vignettes/*.pdf
*.utf8.md
*.knit.md
.Rproj.user

.DS_Store
**/.DS_Store

# Symlink to inst/include for devtools::load_all()
nimbleModel/include
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"makefile.configureOnOpen": false
}
15 changes: 15 additions & 0 deletions nimbleModel.Rproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Version: 1.0

RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8

RnwWeave: Sweave
LaTeX: pdfLaTeX

BuildType: Makefile
6 changes: 5 additions & 1 deletion nimbleModel/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ Authors@R: c(
Description: This package provides the ability to create 'nimble' models, generally hierarchical models, not necessarily Bayesian, in R that are compiled to C++. It includes graph processing tools (e.g., finding dependent and parent nodes), abstractions for efficiently storing variable ranges, e.g., `y[1:5, c(2,4)]` and sets of model nodes (e.g., `y[1,1:5],y[2,1:5],...`), and functions for calculating and simulating variables and nodes in a model. It has been developed to support nimble version 2.0 but can be used more generally for setting up models, doing graph queries and carrying out model calculations.
Depends: R (>= 4.1.0)
Imports:
methods,R6,nCompiler
digest,methods,R6,nCompiler
License: BSD_3_clause + file LICENSE | GPL (>= 2)
Encoding: UTF-8
LazyData: true
Collate:
aaa.R
all_utils.R
context.R
copier.R
dataRules.R
distributions_inputList.R
distributions_processInputList.R
Expand All @@ -39,8 +40,10 @@ Collate:
modelDecl.R
modelDef.R
modelFunctions.R
modelValues.R
model_utils.R
nodeRules.R
opDefs.R
options.R
processModelGraph.R
rhsRules.R
Expand All @@ -52,6 +55,7 @@ Collate:
modelBaseClass.R
instructions.R
nimbleModel.R
zzz.R



19 changes: 19 additions & 0 deletions nimbleModel/NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import(nCompiler)
## Some exports are for testing convenience and may not need to be exported.

## Classes: R6 classes are exported as regular objects
export(copier_nClass)
export(multiCopier_nClass)
export(indexRangeClass)
export(indexRangeEmptyClass)
export(indexRangeScalarClass)
Expand Down Expand Up @@ -79,6 +81,23 @@ export(calc_dwishAltParams)
export(nimbleCode)
export(nimbleModel)
export(makeInstrList)
export(makeMultiCopier)

export(values)
export("values<-")

export(modelValues)
export(modelValuesConf)
export(getsize)
export(resize)

S3method("[", modelValues)
S3method("[<-", modelValues)
S3method("length", modelValues)
S3method("length<-", modelValues)
S3method("as.list", modelValues)
S3method("as.matrix", modelValues)
export(matrix2mv)

export(intersect_nodes)
export(aggregate_nodes)
Expand Down
275 changes: 275 additions & 0 deletions nimbleModel/R/copier.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
# Classes and tools to support nimble2's values() and nimCopy(), both getting and setting.
#
# copier_nClass is just a data structure for one variable name and index information. It doesn't actually copy.
#
# multiCopier_nClass holds multiple copier_nClass's and does values() copying (for a model only).
# It has a C++ layer that uses the flatViewGroup class to do the copying.
#
# multiCopierMV_nClass is like multiCopier_nClass but for modelValues objects,
# but is used only for nimCopy.
#
# multiCopier_nClass and multiCopierMV_nClass share a C++ base class.
# The C++ step of nimCopy_ takes two multiCopier base classes and copies from one to the other.
#
# An important aspect on the C++ side is avoiding repeated name-based lookups of variables
# within the model or modelValues.


#' @export
copier_nClass <- nCompiler::nClass(
classname = "copier_nClass",
Cpublic = list(
varName = "string",
indsList = "nCompiler:::nList(integerVector())"
),
predefined = quote(system.file(file.path("include", "nimbleModel", "predef"), package = "nimbleModel") |> file.path("copier_nClass")),
compileInfo = list(
interface = "full",
createFromR = TRUE,
exportName = "copier_nClass_new",
needed_units = list("nCompiler:::nList(integerVector())"),
packageNames = c(uncompiled = "copier_nClass_R", compiled = "copier_nClass"),
nClass_inherit = list("copier_nC_base")
)
)

#' @export
multiCopier_nClass <- nCompiler::nClass(
classname = "multiCopier_nClass",
Rpublic = list(
initialize = function(...) {
super$initialize(...)
self$copiers <- nList(copier_nClass())$new()
}
),
Cpublic = list(
copiers = "nCompiler:::nList(copier_nClass())",
init = nFunction(
name = "init",
function(model) {
cat("need uncompiled multiCopier init() implementation.")
},
compileInfo = list(
C_fun = function(model = "nimbleModel:::modelBase_nClass()") {
cppLiteral("multiCopier_model_nC_base::init(this->copiers, model)")
}
)
),
getValues = nFunction(
name = "getValues",
function() {
cat("need uncompiled multiCopier getValues() implementation.")
},
returnType = "numericVector",
compileInfo = list(
C_fun = function() {
cppLiteral("return flatViewGroup.copyIntoVector()")
}
)
),
# Note that this setValues works but is not actually used by nimble2 keyword processing
# which instead uses copiers->flatViewGroup.setValues_() which provides an operator=.
# It is possible that this setValues() will be useful in other contexts, or if not that we
# can eventually remove it to avoid confusion.
setValues = nFunction(
name = "setValues",
function(v = "numericVector") {
cat("need uncompiled multiCopier setValues() implementation.")
},
compileInfo = list(
C_fun = function(v = "numericVector") {
cppLiteral("flatViewGroup.copyFromVector(v)")
}
)
)
),
predefined = quote(system.file(file.path("include", "nimbleModel", "predef"), package = "nimbleModel") |> file.path("mCopy_nC")),
compileInfo = list(
cpp_classname = "mCopy_nC",
interface = "full",
createFromR = TRUE,
exportName = "multiCopier_nClass_new",
needed_units = list("nCompiler:::nList(copier_nClass())", "modelBase_nClass()"),
packageNames = c(uncompiled = "multiCopier_nClass_R", compiled = "multiCopier_nClass"),
nClass_inherit = list("multiCopier_model_nC_base"),
opDefs = list(
getOrSetValues = list(
labelAbstractTypes = list(
handler = "multiCopier_getOrSetValues_LAT"
)
)
)
)
)

multiCopier_getOrSetValues_LAT <- function(...) {
browser()
}

#' @export
multiCopierMV_nClass <- nCompiler::nClass(
classname = "multiCopierMV_nClass",
Rpublic = list(
initialize = function(...) {
super$initialize(...)
self$copiers <- nList(copier_nClass())$new()
}
),
Cpublic = list(
copiers = "nCompiler:::nList(copier_nClass())",
init = nFunction(
name = "init",
function(modelValues) {
cat("need uncompiled multiCopierMV init() implementation.")
},
compileInfo = list(
C_fun = function(modelValues = "nimbleModel:::modelValuesBase_nClass()") {
cppLiteral("multiCopier_modelValues_nC_base::init(this->copiers, modelValues)")
}
)
),
# Selects which row of each variable's nList the flatViewGroup reads
# from/writes to. Must be called at least once, after the modelValues has
# been resized to have at least one row, before getValues/setValues/
# nimCopy_ are used. See multiCopier_modelValues_nC_base::setActiveRow.
setActiveRow = nFunction(
name = "setActiveRow",
function(row) {
cat("need uncompiled multiCopierMV setActiveRow() implementation.")
},
compileInfo = list(
C_fun = function(row) {
cppLiteral("multiCopier_modelValues_nC_base::setActiveRow(row)")
}
),
argTypes = list(row = "integerScalar")
),
getValues = nFunction(
name = "getValues",
function() {
cat("need uncompiled multiCopierMV getValues() implementation.")
},
returnType = "numericVector",
compileInfo = list(
C_fun = function() {
cppLiteral("return flatViewGroup.copyIntoVector()")
}
)
),
# See the note on multiCopier_nClass$setValues above: kept for other
# contexts even though nimble2 keyword processing uses
# copiers->flatViewGroup.setValues_() directly.
setValues = nFunction(
name = "setValues",
function(v = "numericVector") {
cat("need uncompiled multiCopierMV setValues() implementation.")
},
compileInfo = list(
C_fun = function(v = "numericVector") {
cppLiteral("flatViewGroup.copyFromVector(v)")
}
)
)
),
predefined = quote(system.file(file.path("include", "nimbleModel", "predef"), package = "nimbleModel") |> file.path("mCopyMV_nC")),
compileInfo = list(
cpp_classaname = "mCopyMV_nC",
interface = "full",
createFromR = TRUE,
exportName = "multiCopierMV_nClass_new",
needed_units = list("nCompiler:::nList(copier_nClass())", "modelValuesBase_nClass()"),
packageNames = c(uncompiled = "multiCopierMV_nClass_R", compiled = "multiCopierMV_nClass"),
nClass_inherit = list("multiCopier_modelValues_nC_base")
)
)

#' @export
makeMultiCopier <- function(source, nodes,
sourceType = c("model", "modelValues"), ...) {
# This will be called from a nimble2 keyword processor
# The ... is to absorb further arguments that at the time of this writing are not fleshed out.
if (is.character(nodes)) {
nodes <- nodes |> lapply(\(x) nimbleModel:::varRangeClass$new(x))
}
sourceType <- match.arg(sourceType)
multiCopier <-
switch(sourceType,
model = multiCopier_nClass$new(),
modelValues = multiCopierMV_nClass$new()
)
getRange <- function(indexRange) {
if (!inherits(indexRange, "indexRangeSequenceClass")) {
stop("In a copy operation, only contiguous index blocks are supported")
}
c(indexRange$start, indexRange$end)
}
for (i in seq_along(nodes)) {
thisNode <- nodes[[i]]
multiCopier$copiers[[i]] <- copier_nClass$new()
multiCopier$copiers[[i]]$varName <- thisNode$varName
multiCopier$copiers[[i]]$indsList <- thisNode$indexRanges |> lapply(getRange)
}
attr(multiCopier, "NCgenerator") <-
switch(sourceType,
model = quote(nimbleModel:::multiCopier_nClass),
modelValues = quote(nimbleModel:::multiCopierMV_nClass)
)
multiCopier
}

# Uncompiled implementations of values(model, nodes) and `values<-`(model, nodes, value).

#' @export
values <- function(model, nodes) {
if (is.character(nodes)) {
nodes <- lapply(nodes, \(x) varRangeClass$new(x))
}
# To-do: other checking and error-trapping on inputs
vals <- lapply(
nodes,
\(x) {
eval(x$toExpr(), envir = model) |> as.numeric()
}
)
do.call("c", vals)
}

#' @export
`values<-` <- function(model, nodes, value) {
if (is.character(nodes)) {
nodes <- lapply(nodes, \(x) varRangeClass$new(x))
}
iV_start <- 1
replExprTemplate <- quote(model_stuff <- value[iV_start:iV_end])
for (i in seq_along(nodes)) {
thisNode <- nodes[[i]]
expr <- thisNode$toExpr()
if (is.name(expr)) {
thisLength <- length(model[[expr]])
} else {
mm <- thisNode$getMinMax()
sizes <- mm[, 2] - mm[, 1] + 1
## This section about NAs in the sizes
## anticipates how we would handle blank index slots
## by putting NAs in the getMinMax() result.
## But that is not in place while this is being drafted
NAsizes <- which(is.na(sizes))
if (length(NAsizes)) {
thisDims <- dimOrLength(model[[thisNode$varName]])
sizes[NAsizes] <- thisDims[NAsizes]
}
#
thisLength <- prod(sizes)
varExpr <- expr[[2]]
model_stuff <- quote(model$VAR)
model_stuff[[3]] <- varExpr
expr[[2]] <- model_stuff
}
iV_end <- iV_start + thisLength - 1
replExpr <- replExprTemplate
replExpr[[2]] <- expr
eval(replExpr)
iV_start <- iV_end + 1
}
model
}
Loading
Loading