@@ -63,6 +63,37 @@ P <- function(trafo = NULL, parameters = NULL, condition = NULL,
6363}
6464
6565
66+ # # Per-condition warm-start registry shared by Pimpl / Pequil / .Pequil_totals.
67+ # # Each of those builds ONE p2p closure even when condition-less, and the common
68+ # # usage pattern is a condition-less `Pequil` (or `Pimpl`) composed via `*` with a
69+ # # condition-specifying `Pexpl`. The prodfn loop then calls that single p2p once
70+ # # per condition. With a single cache env this means every condition warm-starts
71+ # # from whichever condition was solved last (order-dependent, can cross basins of
72+ # # attraction). The registry keeps one cache env PER condition key instead, so a
73+ # # condition is always warm-started from its OWN previous root. `parfn()` forwards
74+ # # the active condition to p2p (see the `condition` argument there); a NULL/empty
75+ # # key (parfn called outside any condition context) falls back to a shared slot.
76+ .warmstart_registry <- function () {
77+ caches <- new.env(parent = emptyenv())
78+ get_cache <- function (key ) {
79+ k <- if (is.null(key ) || ! nzchar(key )) " __default__" else key
80+ cc <- get0(k , envir = caches , inherits = FALSE )
81+ if (is.null(cc )) { cc <- new.env(parent = emptyenv()); assign(k , cc , envir = caches ) }
82+ cc
83+ }
84+ reset <- function () {
85+ nms <- ls(caches , all.names = TRUE )
86+ for (k in nms ) {
87+ cc <- get(k , envir = caches , inherits = FALSE )
88+ inner <- ls(cc , all.names = TRUE )
89+ if (length(inner )) rm(list = inner , envir = cc )
90+ }
91+ invisible (nms )
92+ }
93+ list (get = get_cache , reset = reset , caches = caches )
94+ }
95+
96+
6697# ' Parameter transformation (explicit, algebraic)
6798# '
6899# ' Builds `p_inner = f(p_outer)` from symbolic expressions via
@@ -338,7 +369,7 @@ Pexpl <- function(trafo, parameters = NULL, attach.input = FALSE, condition = NU
338369# ' vanishes at SS; if a feeder's rate involves exactly one state, that
339370# ' state must be zero.
340371# ' \item *Sink cluster (LP)*: subsets whose combined mass leaks
341- # ' monotonically (mass-balance LP via `lpSolve::lp`, only when installed ).
372+ # ' monotonically (mass-balance LP via `lpSolve::lp`).
342373# ' }
343374# ' For each zero-state the column is dropped, the state symbol is substituted
344375# ' by `"0"` in remaining rates, structurally-zero reactions are removed, and
@@ -403,7 +434,6 @@ Pexpl <- function(trafo, parameters = NULL, attach.input = FALSE, condition = NU
403434 }
404435
405436 .sink_cluster <- function (M , eps = 1e-8 , Mbig = 1e4 ) {
406- if (! requireNamespace(" lpSolve" , quietly = TRUE )) return (integer(0 ))
407437 nF <- nrow(M ); nS <- ncol(M )
408438 if (nF == 0L || nS == 0L ) return (integer(0 ))
409439 c_obj <- colSums(M )
@@ -805,8 +835,7 @@ Pimpl <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
805835 array (c(H4 ), dim(H4 )[2 : 4 ], dimnames = dimnames(H4 )[2 : 4 ])
806836 }
807837
808- cache <- new.env(parent = emptyenv())
809- cache $ guess <- NULL
838+ reg <- .warmstart_registry()
810839
811840 # # Biological SS magnitudes span ~10 orders when rate constants span 2-3:
812841 # # default log-uniform sampling over [1e-5, 1e5] when positive = TRUE.
@@ -962,12 +991,13 @@ Pimpl <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
962991 }
963992
964993
965- p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE ) {
994+ p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE , condition = NULL ) {
966995 if (deriv2 && ! emit_d2 )
967996 stop(" Pimpl was built with deriv2 = FALSE; rebuild with deriv2 = TRUE." , call. = FALSE )
968997 if (! emit_d1 ) deriv <- FALSE
969998 if (deriv2 && ! deriv ) deriv <- TRUE
970999
1000+ cache <- reg $ get(condition )
9711001 p <- pars
9721002 dP <- attr(p , " deriv" )
9731003 dP2 <- if (deriv2 ) attr(p , " deriv2" ) else NULL
@@ -1086,9 +1116,9 @@ Pimpl <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
10861116 attr(p2p , " modelname" ) <- modelname
10871117 attr(p2p , " compileInfo" ) <- collectCompileInfo(PEval $ func , PEval $ jac , PEval $ hess )
10881118 attr(p2p , " resetWarmStart" ) <- local({
1089- cache_ref <- cache ; mn <- modelname ; cond <- condition
1119+ reg_ref <- reg ; mn <- modelname ; cond <- condition
10901120 function () {
1091- cache_ref $ guess <- NULL
1121+ reg_ref $ reset()
10921122 paste0(" Pimpl(" , mn , if (! is.null(cond )) paste0(" :" , cond ) else " " , " )" )
10931123 }
10941124 })
@@ -1198,21 +1228,21 @@ Pimpl <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
11981228 controls <- c(list (keep.root = keep.root , attach.input = attach.input ,
11991229 start.time = start.time , end.time = end.time ), ode_ctrl )
12001230
1201- cache <- new.env(parent = emptyenv())
1202- cache $ yini <- cache $ last_hash <- cache $ last_result <- NULL
1231+ reg <- .warmstart_registry()
12031232
12041233 default_sens <- matrix (0 , n_dep , length(all_sens ), dimnames = list (dependent , all_sens ))
12051234 if (length(pivots )) default_sens [cbind(pivots , pivots )] <- 1
12061235 default_sens2 <- if (emit_d2 )
12071236 array (0 , c(n_dep , length(all_sens ), length(all_sens )),
12081237 dimnames = list (dependent , all_sens , all_sens )) else NULL
12091238
1210- p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE ) {
1239+ p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE , condition = NULL ) {
12111240 if (deriv2 && ! emit_d2 )
12121241 stop(" Pequil(deriv2 = TRUE) requires the model to be built with deriv2 = TRUE." ,
12131242 call. = FALSE )
12141243 if (! emit_d1 ) deriv <- FALSE
12151244 if (deriv2 && ! deriv ) deriv <- TRUE
1245+ cache <- reg $ get(condition )
12161246 p <- pars
12171247 dP <- attr(p , " deriv" )
12181248 dP2 <- if (deriv2 ) attr(p , " deriv2" ) else NULL
@@ -1352,9 +1382,9 @@ Pimpl <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
13521382 attr(p2p , " modelname" ) <- modelname
13531383 attr(p2p , " compileInfo" ) <- collectCompileInfo(model , model_s , model_s2 )
13541384 attr(p2p , " resetWarmStart" ) <- local({
1355- cache_ref <- cache ; mn <- modelname ; cond <- condition
1385+ reg_ref <- reg ; mn <- modelname ; cond <- condition
13561386 function () {
1357- cache_ref $ yini <- cache_ref $ last_hash <- cache_ref $ last_result <- NULL
1387+ reg_ref $ reset()
13581388 paste0(" Pequil(" , mn , if (! is.null(cond )) paste0(" :" , cond ) else " " , " )" )
13591389 }
13601390 })
@@ -1465,9 +1495,7 @@ Pequil <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
14651495 maxprogress = 100L , hini = 0 , roottol = 1e-6 , maxroot = 1L ),
14661496 controlsODE )
14671497
1468- cache <- new.env(parent = emptyenv())
1469- cache $ yini <- cache $ sensini <- cache $ sens2ini <-
1470- cache $ last_hash <- cache $ last_result <- NULL
1498+ reg <- .warmstart_registry()
14711499
14721500 default_sens <- matrix (0 , n_dep , length(all_sens ),
14731501 dimnames = list (dependent , all_sens ))
@@ -1480,13 +1508,14 @@ Pequil <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
14801508 controls <- c(list (keep.root = keep.root , attach.input = attach.input ,
14811509 start.time = start.time , end.time = end.time ), ode_ctrl )
14821510
1483- p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE ) {
1511+ p2p <- function (pars , fixed = NULL , deriv = TRUE , deriv2 = FALSE , condition = NULL ) {
14841512 if (deriv2 && ! emit_d2 )
14851513 stop(" Pequil(deriv2 = TRUE) requires the model to be built with deriv2 = TRUE." ,
14861514 call. = FALSE )
14871515 if (! emit_d1 ) deriv <- FALSE
14881516 if (deriv2 && ! deriv ) deriv <- TRUE
14891517
1518+ cache <- reg $ get(condition )
14901519 p <- pars
14911520 dP <- attr(p , " deriv" )
14921521 dP2 <- if (deriv2 ) attr(p , " deriv2" ) else NULL
@@ -1658,10 +1687,9 @@ Pequil <- function(trafo, parameters = NULL, forcings = NULL, condition = NULL,
16581687 attr(p2p , " modelname" ) <- modelname
16591688 attr(p2p , " compileInfo" ) <- collectCompileInfo(model , model_s , model_s2 )
16601689 attr(p2p , " resetWarmStart" ) <- local({
1661- cache_ref <- cache ; mn <- modelname ; cond <- condition
1690+ reg_ref <- reg ; mn <- modelname ; cond <- condition
16621691 function () {
1663- cache_ref $ yini <- cache_ref $ sensini <- cache_ref $ sens2ini <-
1664- cache_ref $ last_hash <- cache_ref $ last_result <- NULL
1692+ reg_ref $ reset()
16651693 paste0(" Pequil(" , mn , if (! is.null(cond )) paste0(" :" , cond ) else " " , " )" )
16661694 }
16671695 })
0 commit comments