Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion nimbleModel/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Collate:
indexConstraint.R
getSymbolicParentNodes.R
graphRules.R
loopIndexingRules.R
MCMC_configuration.R
MCMC_conjugacy.R
MCMC_utils.R
Expand All @@ -41,7 +42,6 @@ Collate:
model_utils.R
nodeRules.R
options.R
originalIndexingRules.R
processModelGraph.R
rhsRules.R
types_util.R
Expand Down
3 changes: 2 additions & 1 deletion nimbleModel/NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export(declRuleClass)
export(rhsRuleClass)
export(calcRuleClass)
export(calcRangeClass)
export(originalIndexingRuleClass)
export(loopIndexingRuleClass)
export(loopIndexingRangeClass)

## functions and other objects
export(makeCalcRules)
Expand Down
4 changes: 2 additions & 2 deletions nimbleModel/R/MCMC_configuration.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ samplerConfClass <- R6Class(
},
toStr = function(displayControlDefaults = FALSE, displayNonScalars = FALSE, displayConjugateDependencies = FALSE) {
tempList <- list()
tempList[[paste0(name, " sampler")]] <- paste0(target, collapse = ", ")
tempList[[paste0(name, " sampler")]] <- paste0(target$toNodeChars(), collapse = ", ")
infoList <- c(tempList, control)
mcmc_listContentsToStr(infoList, displayControlDefaults, displayNonScalars, displayConjugateDependencies)
},
Expand Down Expand Up @@ -219,7 +219,7 @@ mcmcConfClass <- R6Class(
dynamicallyIndexed = model$modelDef$varInfo[[target$varName]]$anyDynamicallyIndexed
))
}
stop("Cannot assign conjugate sampler to non-conjugate node: `", target, "`")
stop("Cannot assign conjugate sampler to non-conjugate node: `", target$toNodeChars(), "`")
}

if (targetAsScalars) {
Expand Down
29 changes: 19 additions & 10 deletions nimbleModel/R/graphRules.R
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,13 @@ applyGraphRule <- function(fromVarRange, rule, varName = NULL, removeDuplicates
}

if (!length(indexRules)) {
return(
varRangeClass$new(ifelse(is.null(varName), rule$toVarName, varName),
fromStochRule = rule$stoch
)
)
if(rule$toVarName == ".loop") {
return(loopIndexingRangeClass$new(ifelse(is.null(varName), rule$toVarName, varName),
fromStochRule = NULL))
} else {
return(varRangeClass$new(ifelse(is.null(varName), rule$toVarName, varName),
fromStochRule = rule$stoch))
}
}

# Step 1: Apply indexRules one by one, getting inputs from multiple indexRanges if necessary.
Expand Down Expand Up @@ -701,14 +703,21 @@ applyGraphRule <- function(fromVarRange, rule, varName = NULL, removeDuplicates
# Remove duplicate columns (from cases where two indexRanges are used in a single rule).
repeats <- duplicated(finalRangeToIndexSlot)

return(
varRangeClass$new(
if(rule$toVarName == ".loop") {
return(loopIndexingRangeClass$new(
indexInfo = finalIndexRanges[!repeats],
rangeToIndexSlot = finalRangeToIndexSlot[!repeats],
varName = ifelse(is.null(varName), rule$toVarName, varName),
fromStochRule = rule$stoch
)
)
fromStochRule = NULL))
} else {
return(
varRangeClass$new(
indexInfo = finalIndexRanges[!repeats],
rangeToIndexSlot = finalRangeToIndexSlot[!repeats],
varName = ifelse(is.null(varName), rule$toVarName, varName),
fromStochRule = rule$stoch
))
}
}


Expand Down
11 changes: 11 additions & 0 deletions nimbleModel/R/indexRuleArbitrary.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ indexRuleArbitraryClass <- R6Class(
},
getNumElements = function() {
return(setupResults$unrolledSize)
},
getIDs = function(indexRange) {
values <- match(indexRange$getValuesAsMatrix(), unlist(setupResults$iRow2toIndices))
NAs <- is.na(values)
if (any(NAs)) {
values <- values[!NAs]
}
return(values)
},
invertIDs = function(relativeNodeIDs) {
unlist(setupResults$iRow2toIndices[relativeNodeIDs])
}
)
)
Expand Down
16 changes: 16 additions & 0 deletions nimbleModel/R/indexRuleBlock.R
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ indexRuleBlockClass <- R6Class(
},
getNumElements = function() {
return(setupResults$fromMax - setupResults$fromMin + 1)
},
getIDs = function(indexRange) {
init <- setupResults$fromMin + setupResults$offset
switch(class(indexRange)[1],
indexRangeScalarClass = indexRange$value - init + 1,
indexRangeSequenceClass = (indexRange$start - init + 1):(indexRange$end - init + 1),
indexRangeMatrixClass = c(indexRange$values) - init + 1,
stop("invalid type of indexRange provided for creating IDs")
)
},
invertIDs = function(relativeNodeIDs) {
if (setupResults$fromMin + setupResults$offset != 1) {
return(relativeNodeIDs + (setupResults$fromMin + setupResults$offset - 1))
} else {
return(relativeNodeIDs)
}
}
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# An originalIndexingRuleClass object represents the relationship
# An loopIndexingRuleClass object represents the relationship
# between the loop indexing and the indexing of a LHS variable,
# such as giving the values of `i` when provided a varRange for `y` in
# `for(i in 5:n) y[i-2] <- 1`, such that `y[7:9]` would give `i=9:11`.


originalIndexingRuleClass <- R6Class(
classname = "originalIndexingRuleClass",
loopIndexingRuleClass <- R6Class(
classname = "loopIndexingRuleClass",
portable = FALSE,
public = list(
graphRule = NULL,
indexSlotToSet = NULL,
externalRule = NULL,
internalRule = NULL,
decl = NULL,
varName = character(),
initialize = function(LHS,
context,
constants = list()) {
constants = list(),
decl = NULL) {
varName <<- getVarName(LHS)
decl <<- decl
if (length(context$indexVarNames)) {
# Exclude indices not used in lifted expression, e.g., `i` in `y[i,j] ~ dnorm(mu[i], var = sigma2[j])`
indexVarNames <- context$indexVarNames
Expand All @@ -26,10 +29,10 @@ originalIndexingRuleClass <- R6Class(
} else {
""
}
dummyLHS <- parse(text = paste0(varName, indexing))[[1]]
dummyLHS <- parse(text = paste0(".loop", indexing))[[1]]
# Unused singleContexts will be removed in graphRuleClass$new().
} else {
dummyLHS <- as.name(varName)
dummyLHS <- as.name(".loop")
}

graphRule <<- graphRuleClass$new(
Expand All @@ -39,7 +42,7 @@ originalIndexingRuleClass <- R6Class(
constants
)

# For use in apply_reverse; we want to produce nodeRanges, not varRanges.
# For use in `invert`; we want to produce nodeRanges, not varRanges.
fullRule <- graphRuleClass$new(
LHS,
dummyLHS,
Expand Down Expand Up @@ -72,9 +75,6 @@ originalIndexingRuleClass <- R6Class(
}
},

# Produces a varRange, though it's not really a range for a variable
# but rather a range for the indices.
# (2023-06-10, commit 30ede6)
# Do not remove duplicates because in generation of `calcRange`s there
# can be cases where we need duplicated values in order to have correct
# number of logProbs.
Expand All @@ -88,7 +88,8 @@ originalIndexingRuleClass <- R6Class(
apply = function(fromVarRange) {
graphRule$apply(fromVarRange, removeDuplicates = TRUE)
},
apply_reverse = function(indexingRange, decl) {
# TODO: or we could name this loopIndexingToNodes or some such.
invert = function(indexingRange) {
if (length(externalRule$indexRules)) {
externalRange <- externalRule$apply(indexingRange)
if (is.null(externalRange)) {
Expand All @@ -98,12 +99,41 @@ originalIndexingRuleClass <- R6Class(
externalRange <- varRangeClass$new(list())
}
if (length(internalRule$indexRules)) {
internalRange <- internalRule$apply(externalRule$getFromRange()) # This needs to be instantiated anew to avoid having multiple references to the internalRange indexRanges.
# This needs to be instantiated anew to avoid having multiple references to the internalRange indexRanges.
internalRange <- internalRule$apply(externalRule$getFromRange())
} else {
internalRange <- varRangeClass$new(list())
}

# Note that the varName is determined from self$varName (indexingRange has .loop as varName).
return(nodeRangeClass$new(varName, externalRange, internalRange, indexSlotToSet, decl))
}
)
)

loopIndexingRangeClass <- R6Class(
"loopIndexingRangeClass",
portable = FALSE,
inherit = varRangeClass,
public = list(
initialize = function(indexInfo,
rangeToIndexSlot = NULL,
varName = ".loop",
fromStochRule = NULL) {
super$initialize(indexInfo, rangeToIndexSlot, varName, fromStochRule)
},
toChar = function() {
dots <- sapply(indexRangeExprs, identical, quote(...))
if(all(dots))
return("nonseparable loop indexing")
text <- paste0("index ", seq_along(indexRangeExprs[!dots]), ": ")
text <- paste0(text, indexRangeExprs[!dots], collapse = ", ")
if(any(dots)) text <- paste0(text, ", plus nonseparable loop indexing")
return(text)
},
print = function() {
cat("looping with ", toChar(), ".\n", sep = "")
}
)
)


8 changes: 4 additions & 4 deletions nimbleModel/R/modelBaseClass.R
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,8 @@ modelBase_nClass <- nClass(
stop("getParamExpr: `", param, "` is not present in the parameterization")
}
if (length(expr) > 1) {
# Substitute original index values into the expression.
indexVarRange <- decl$declRule$originalIndexingRule$apply(nodeRange)
# Substitute looping index values into the expression.
indexVarRange <- decl$declRule$loopIndexingRule$apply(nodeRange)
indexValues <- indexVarRange$indexRangeExprs
names(indexValues) <- decl$context$indexVarNames
expr <- eval(substitute(substitute(EXPR, indexValues), list(EXPR = expr)))
Expand All @@ -358,8 +358,8 @@ modelBase_nClass <- nClass(
expr <- expr[!names(expr) %in% c("lower_", "upper_") &
!grepl("^\\.", names(expr))]
}
# Substitute original index values into the expression.
indexVarRange <- decl$declRule$originalIndexingRule$apply(nodeRange)
# Substitute loop index values into the expression.
indexVarRange <- decl$declRule$loopIndexingRule$apply(nodeRange)
indexValues <- indexVarRange$indexRangeExprs
names(indexValues) <- decl$context$indexVarNames
expr <- eval(substitute(substitute(EXPR, indexValues), list(EXPR = expr)))
Expand Down
4 changes: 2 additions & 2 deletions nimbleModel/R/modelDecl.R
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ modelDeclClass <- R6Class(
# Create declRule and symbolic RHS pieces.
processDecl = function(nimFunNames, constants = list(), envir) {
declRule <<- declRuleClass$new(self, 0, context, constants)
if (length(declRule$originalIndexingRule$graphRule$indexRules)) {
if (length(declRule$loopIndexingRule$graphRule$indexRules)) {
if (!identical(
declRule$externalRule$apply(declRule$varName)$extractIndexRange()$numElements,
declRule$originalIndexingRule$apply(declRule$varName)$extractIndexRange()$numElements
declRule$loopIndexingRule$apply(declRule$varName)$extractIndexRange()$numElements
) &&
!any(sapply(indexExpr, checkForIndexedIntervals, context))) { # Non-constant indexing invalidates this check.
stop("found duplicated node definitions in declaring `", safeDeparse(declRule$expr), "`.")
Expand Down
23 changes: 7 additions & 16 deletions nimbleModel/R/modelFunctions.R
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,7 @@ aggregate_nodes <- function(nodeSet) {
newNodeSet <- lapply(seq_along(IDsByDecl), \(i) {
if(sum(nms[i] == declIDs) > 1) {
whichDecl <- match(nms[i], declIDs)
decl <- nodeSet[[whichDecl]]$decl
return(decl$declRule$originalIndexingRule$apply_reverse(
decl$declRule$getOriginalIndexing(IDsByDecl[[i]]), decl
))
return(nodeSet[[whichDecl]]$decl$declRule$getNodesFromIDs(IDsByDecl[[i]]))
} else return(nodeSet[[nms[i]]])
})
return(c(newNodeSet, RHSonly))
Expand All @@ -310,9 +307,7 @@ intersect_nodes <- function(nodeSet1, nodeSet2) {
if (declIDs1[i] == declIDs2[j]) intersect(nodeIDs1[[i]], nodeIDs2[[j]]) else NULL
})))
if (length(keepNodeIDs)) {
newNodeSet1[[i]] <- nodeSet1[[i]]$decl$declRule$originalIndexingRule$apply_reverse(
nodeSet1[[i]]$decl$declRule$getOriginalIndexing(keepNodeIDs), nodeSet1[[i]]$decl
)
newNodeSet1[[i]] <- nodeSet1[[i]]$decl$declRule$getNodesFromIDs(keepNodeIDs)
}
}
return(newNodeSet1[!sapply(newNodeSet1, is.null)])
Expand Down Expand Up @@ -347,9 +342,7 @@ setdiff_nodes <- function(nodeSet1, nodeSet2) {
for (i in seq_along(nodeSet1)) {
keepNodeIDs <- setdiff(nodeIDs1[[i]], excludeNodeIDs[[declIDs1[i]]])
if (length(keepNodeIDs)) {
newNodeSet1[[i]] <- nodeSet1[[i]]$decl$declRule$originalIndexingRule$apply_reverse(
nodeSet1[[i]]$decl$declRule$getOriginalIndexing(keepNodeIDs), nodeSet1[[i]]$decl
)
newNodeSet1[[i]] <- nodeSet1[[i]]$decl$declRule$getNodesFromIDs(keepNodeIDs)
}
}
return(c(newNodeSet1[!sapply(newNodeSet1, is.null)], RHSonly))
Expand Down Expand Up @@ -455,9 +448,7 @@ getConditionallyIndependentSets <- function(model, nodes, givenNodes, omit = NUL
this_touched <- touched[[focalNodeRange$decl$declRule$ID]]$tagged[focalNodeIDs]
while (!all(this_touched)) {
focalNodeID <- focalNodeIDs[!this_touched][1]
currentNode <- focalNodeRange$decl$declRule$originalIndexingRule$apply_reverse( # indexing range to nodeRange
focalNodeRange$decl$declRule$getOriginalIndexing(focalNodeID), focalNodeRange$decl
) # ID to indexing range
currentNode <- focalNodeRange$decl$declRule$getNodesFromIDs(focalNodeID)
sets[[numSets]] <- getOneConditionallyIndependentSet(model, currentNode, focalNodeID, given, touched,
startUp = startUp, startDown = startDown
)
Expand Down Expand Up @@ -508,7 +499,7 @@ exploreDown <- function(ans, model, currentNodes, given, touched) {
newLatentNodes <- child
} else {
newLatentIDs <- childIDs[chosen]
newLatentNodes <- child$decl$declRule$originalIndexingRule$apply_reverse(child$decl$declRule$getOriginalIndexing(newLatentIDs), child$decl)
newLatentNodes <- child$decl$declRule$getNodesFromIDs(newLatentIDs)
}
ans[[length(ans) + 1]] <- newLatentNodes
} else {
Expand All @@ -520,7 +511,7 @@ exploreDown <- function(ans, model, currentNodes, given, touched) {
} else {
upIDsFromGiven <- childIDs[chosen]
if (length(upIDsFromGiven)) {
upNodesFromGiven <- child$decl$declRule$originalIndexingRule$apply_reverse(child$decl$declRule$getOriginalIndexing(upIDsFromGiven), child$decl)
upNodesFromGiven <- child$decl$declRule$getNodesFromIDs(upIDsFromGiven)
} else {
upNodesFromGiven <- NULL
}
Expand Down Expand Up @@ -552,7 +543,7 @@ exploreUp <- function(ans, model, currentNodes, given, touched) {
newLatentNodes <- parent
} else {
newLatentIDs <- parentIDs[chosen]
newLatentNodes <- parent$decl$declRule$originalIndexingRule$apply_reverse(parent$decl$declRule$getOriginalIndexing(newLatentIDs), parent$decl)
newLatentNodes <- parent$decl$declRule$getNodesFromIDs(newLatentIDs)
}
ans[[length(ans) + 1]] <- newLatentNodes
ans <- exploreUp(ans, model, newLatentNodes, given, touched)
Expand Down
Loading