Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add modifying models article #620

Merged
merged 26 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ee734f3
Add modifying models article
mattfidler Dec 2, 2023
0ca7897
Merge remote-tracking branch 'origin/main' into 563-write-info-about-…
mattfidler Dec 5, 2023
6a5a386
Merge branch 'main' into 563-write-info-about-model-piping
mattfidler Dec 5, 2023
89962fa
add more information on piping
mattfidler Dec 5, 2023
909fee8
Merge branch 'main' into 563-write-info-about-model-piping
mattfidler Dec 5, 2023
880b62b
Add more information about parameter promotion
mattfidler Dec 5, 2023
e7971e5
example re-arranging parameters
mattfidler Dec 5, 2023
303a192
Merge branch '625-inconsistent-append-behavior-between-ini-and-model-…
mattfidler Dec 5, 2023
d1ffdd9
Align piping in vignette
mattfidler Dec 5, 2023
d52eea0
Merge branch '625-inconsistent-append-behavior-between-ini-and-model-…
mattfidler Dec 5, 2023
eb58c25
Merge remote-tracking branch 'origin/629-mem-issues' into 563-write-i…
mattfidler Dec 6, 2023
700f550
fix model()<- example
mattfidler Dec 6, 2023
b4a3796
Merge branch 'main' into 563-write-info-about-model-piping
mattfidler Dec 6, 2023
e06cb89
Re-export toTrialDuration
mattfidler Dec 6, 2023
14e5a05
Add ini data frame modification example
mattfidler Dec 6, 2023
af801af
Fix camelCase instead of snake_case
mattfidler Dec 7, 2023
9bcbfd3
prefer params over omega/sigma
mattfidler Dec 7, 2023
5613db5
Change rxRename to rename everything in one pass
mattfidler Dec 8, 2023
8e2aede
Fix errors in vignette
mattfidler Dec 8, 2023
74b64dd
add to pkgdown index
mattfidler Dec 8, 2023
11388cd
be more careful with 1x1 sigma/omega matrices
mattfidler Dec 8, 2023
9b92ad7
Some fixes for plot
mattfidler Dec 8, 2023
889c3ba
Comment out plotLog for now
mattfidler Dec 8, 2023
8665e32
Add back
mattfidler Dec 8, 2023
386cd10
Add rename for thetaMat and sigma if present
mattfidler Dec 8, 2023
c73a698
Add tests and fixes for rxRename (w/sigma and thetaMat)
mattfidler Dec 8, 2023
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: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ export(scale_y_discrete)
export(setRxThreads)
export(stat_amt)
export(stat_cens)
export(toTrialDuration)
export(uppergamma)
export(waiver)
export(write.template.server)
Expand Down Expand Up @@ -534,6 +535,7 @@ importFrom(rxode2et,rxEvid)
importFrom(rxode2et,rxRateDur)
importFrom(rxode2et,rxReq)
importFrom(rxode2et,rxStack)
importFrom(rxode2et,toTrialDuration)
importFrom(rxode2parse,.getLastIdLvl)
importFrom(rxode2parse,forderForceBase)
importFrom(rxode2parse,rxDerived)
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ mu-referencing style to run the optimization.
`ini(param=NULL)` changes the parameter to a covariate to align with
this idiom of dropping parameters

- `rxRename` has been refactored to run faster

## Internal new features

- Add `as.model()` for list expressions, which implies `model(ui) <-
Expand All @@ -188,6 +190,9 @@ mu-referencing style to run the optimization.

## Bug fixes

- Simulating/solving from functions/ui now prefers params over `omega`
and `sigma` in the model (#632)

- Piping does not add constants to the initial estimates

- When constants are specified in the `model({})` block (like `k <- 1`), they will not
Expand Down
8 changes: 4 additions & 4 deletions R/piping-ini.R
Original file line number Diff line number Diff line change
Expand Up @@ -402,18 +402,18 @@
# Do nothing
return()
} else if (is.logical(append)) {
checkmate::assert_logical(append, any.missing = FALSE, len = 1)
checkmate::assertLogical(append, any.missing = FALSE, len = 1)
if (isTRUE(append)) {
appendClean <- Inf
} else if (isFALSE(append)) {
appendClean <- 0
}
} else if (is.numeric(append)) {
checkmate::assert_number(append, null.ok = FALSE, na.ok = FALSE)
checkmate::assertNumber(append, null.ok = FALSE, na.ok = FALSE)
appendClean <- append
} else if (is.character(append)) {
checkmate::assert_character(append, any.missing = FALSE, len = 1, null.ok = FALSE)
checkmate::assert_choice(append, choices = ini$name)
checkmate::assertCharacter(append, any.missing = FALSE, len = 1, null.ok = FALSE)
checkmate::assertChoice(append, choices = ini$name)
appendClean <- which(ini$name == append)
} else {
stop("'append' must be NULL, logical, numeric, or character/expression of variable in model",
Expand Down
4 changes: 2 additions & 2 deletions R/plot.R
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ rxTheme <- function(base_size = 11, base_family = "",
stopifnot(length(log) == 1)
stopifnot(is.character(log))
stopifnot(log %in% c("", "x", "y", "xy", "yx"))
useLogX <- nchar(log) == 2 | log == "x"
useLogY <- nchar(log) == 2 | log == "y"
useLogX <- nchar(log) == 2L || log == "x"
useLogY <- nchar(log) == 2L || log == "y"
useXgxr <-
getOption("rxode2.xgxr", TRUE) &&
requireNamespace("xgxr", quietly = TRUE)
Expand Down
4 changes: 4 additions & 0 deletions R/reexport.R
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,7 @@ rxode2parse::.getLastIdLvl
#' @importFrom rxode2random .expandPars
#' @export
rxode2random::.expandPars

#' @importFrom rxode2et toTrialDuration
#' @export
rxode2et::toTrialDuration
41 changes: 39 additions & 2 deletions R/rxsolve.R
Original file line number Diff line number Diff line change
Expand Up @@ -1157,16 +1157,17 @@ rxSolve.function <- function(object, params = NULL, events = NULL, inits = NULL,
.lst <- list(...)
.nlst <- names(.lst)
.w <- which(vapply(names(.ctl), function(x) {
!(x %in% names(.nlst)) && exists(x, envir=.meta)
!(x %in% .nlst) && exists(x, envir=.meta)
}, logical(1), USE.NAMES=FALSE))
.extra <- NULL
if (length(.w) > 0) {
.v <- names(.ctl)[.w]
.minfo(paste0("rxControl items read from fun: '",
paste(.v, collapse="', '"), "'"))
paste(.v, collapse="', '"), "'"))
.extra <- setNames(lapply(.v, function(x) {
get(x, envir=.meta)
}), .v)

}
do.call(rxSolve, c(list(NULL, params = NULL, events = NULL, inits = NULL),
.lst, .extra,
Expand Down Expand Up @@ -1220,6 +1221,24 @@ rxSolve.function <- function(object, params = NULL, events = NULL, inits = NULL,
.rxControl$omega <- NULL
}
}
if (inherits(.rxControl$omega, "matrix")) {
.omega <- .rxControl$omega
.v <- vapply(dimnames(.omega)[[1]],
function(v) {
!(v %in% names(params))
}, logical(1), USE.NAMES = FALSE)
if (length(.v) == 1L) {
if (!.v) .rxControl$omega <- NULL
} else {
.omega <- .omega[.v, .v]
if (all(dim(.omega) == c(0L, 0L))) {
.rxControl$omega <- NULL
} else {
.rxControl$omega <- .omega
}
}

}
if (inherits(.rxControl$omega, "matrix") &&
all(dim(.rxControl$omega) == c(0,0))) {
.rxControl$omega <- NULL
Expand All @@ -1235,6 +1254,24 @@ rxSolve.function <- function(object, params = NULL, events = NULL, inits = NULL,
.rxControl$sigma <- NULL
}
}
if (inherits(.rxControl$sigma, "matrix")) {
.sigma <- .rxControl$sigma
.v <- vapply(dimnames(.sigma)[[1]],
function(v) {
!(v %in% names(params))
}, logical(1), USE.NAMES = FALSE)
if (length(.v) == 1L) {
if (!.v) .rxControl$sigma <- NULL
} else {
.sigma <- .sigma[.v, .v, drop = FALSE]
if (all(dim(.sigma) == c(0L, 0L))) {
.rxControl$sigma <- NULL
} else {
.rxControl$sigma <- .sigma
}
}

}
if (inherits(.rxControl$sigma, "matrix") &&
all(dim(.rxControl$sigma) == c(0,0))) {
.rxControl$sigma <- NULL
Expand Down
163 changes: 126 additions & 37 deletions R/ui-rename.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,68 +41,149 @@
}
list(line[[2]], line[[3]], .var.name, .var.name2)
}

#' Rename variables in the expression
#' Renames everything in one function
#'
#' @param item Expression to recursively rename
#' @param new New name
#' @param old Old name
#' @return new expression with variable renamed
#' @author Matthew L. Fidler
#' @param item language item to process
#' @param lst list of renaming from .assertRenameErrorModelLine, ie list(new, old, newChar, oldChar)
#' @param isLhs is the expression the left handed side of the equation
#' @return expression renamed
#' @noRd
.rxRenameRecursive <- function(item, new, old, isLhs=FALSE) {
#' @author Matthew L. Fidler
.rxRenameRecursiveAll <- function(item, lst, isLhs=FALSE) {
if (is.atomic(item)) {
return(item)
}
if (is.name(item)) {
if (identical(item, old)) {
return(new)
} else {
return(item)
.env <- new.env(parent=emptyenv())
.env$new <- NULL
lapply(seq_along(lst), function(i) {
if (!is.null(.env$new)) return(NULL)
.curLst <- lst[[i]]
.old <- .curLst[[2]]
if (identical(item, .old)) {
.env$new <- .curLst[[1]]
}
return(NULL)
})
if (!is.null(.env$new)) {
return(.env$new)
}
return(item)
} else if (is.call(item)) {
if (isLhs && identical(item[[1]], quote(`/`))) {
# handle d/dt() differently so that d doesn't get renamed
.num <- item[[2]]
.denom <- item[[3]]
if (is.call(.num)) .num <- as.call(lapply(.num, .rxRenameRecursive, new=new, old=old, isLhs=TRUE))
if (is.call(.denom)) .denom <- as.call(lapply(.denom, .rxRenameRecursive, new=new, old=old, isLhs=TRUE))
if (is.call(.num)) .num <- as.call(lapply(.num, .rxRenameRecursiveAll, lst=lst, isLhs=TRUE))
if (is.call(.denom)) .denom <- as.call(lapply(.denom, .rxRenameRecursiveAll, lst=lst, isLhs=TRUE))
return(as.call(c(list(item[[1]]), .num, .denom)))
} else if (isLhs && identical(item[[1]], old) && length(item) == 2L &&
} else if (isLhs && length(item) == 2L &&
is.numeric(item[[2]])) {
# handle x(0) = items
return(as.call(c(new, lapply(item[-1], .rxRenameRecursive, new=new, old=old, isLhs=isLhs))))
.env <- new.env(parent=emptyenv())
.env$new <- NULL
lapply(seq_along(lst),
function(i) {
if (!is.null(.env$new)) return(NULL)
.curLst <- lst[[i]]
.old <- .curLst[[2]]
if (identical(item[[1]], .old)) {
.env$new <- .curLst[[1]]
}
return(NULL)
})
if (!is.null(.env$new)) {
# handle x(0) = items
return(as.call(c(.env$new, lapply(item[-1], .rxRenameRecursiveAll, lst=lst, isLhs=isLhs))))
}
}
if (identical(item[[1]], quote(`=`)) ||
identical(item[[1]], quote(`<-`)) ||
identical(item[[1]], quote(`~`))) {
.elhs <- lapply(item[c(-1, -3)], .rxRenameRecursive, new=new, old=old, isLhs=TRUE)
.erhs <- lapply(item[c(-1, -2)], .rxRenameRecursive, new=new, old=old, isLhs=FALSE)
.elhs <- lapply(item[c(-1, -3)], .rxRenameRecursiveAll, lst=lst, isLhs=TRUE)
.erhs <- lapply(item[c(-1, -2)], .rxRenameRecursiveAll, lst=lst, isLhs=FALSE)
return(as.call(c(item[[1]], .elhs, .erhs)))
} else {
return(as.call(c(list(item[[1]]), lapply(item[-1], .rxRenameRecursive, new=new, old=old, isLhs=isLhs))))
return(as.call(c(list(item[[1]]), lapply(item[-1], .rxRenameRecursiveAll, lst=lst, isLhs=isLhs))))
}
} else {
stop("unknown expression", call.=FALSE)
}
}
#' Rename one item in the rxui
#' Rename all items in matrix dimnames
#'
#' @param rxui rxui for renaming
#' @param lst list with (new, old, newChr, oldChr)
#' @return Nothing, called for side effects
#' @param mat matrix
#' @param lst list for renaming
#' @return renamed matrix
#' @noRd
#' @author Matthew L. Fidler
.rxRenameAllMat <- function(mat, lst) {
.d <- dimnames(mat)[[1]]
.d <- vapply(seq_along(.d), function(i) {
.env <- new.env(parent=emptyenv())
.env$new <- NULL
.cur <- .d[i]
lapply(seq_along(lst),
function(j) {
if (!is.null(.env$new)) return(NULL)
.curLst <- lst[[j]]
.old <- .curLst[[4]]
if (.cur == .old) {
.env$new <- .curLst[[3]]
}
})
if (!is.null(.env$new)) return(.env$new)
return(.cur)
}, character(1), USE.NAMES=FALSE)
dimnames(mat) <- list(.d, .d)
mat
}

#' Rename all the items in the initialization data frame and model
#'
#' @param rxui the ui to process
#' @param lst the list of old and new expressions (like above)
#' @return Called for side effects
#' @noRd
.rxRename1 <- function(rxui, lst) {
#' @author Matthew L. Fidler
.rxRenameAll <- function(rxui, lst) {
rxui <- rxUiDecompress(rxui)
.iniDf <- rxui$iniDf
.w <- which(.iniDf$name == lst[[4]])
if (length(.w) == 1) {
.iniDf$name[.w] <- lst[[3]]
rxui$iniDf <- .iniDf
.iniDf$name <- vapply(seq_along(.iniDf$name),
function(i) {
.env <- new.env(parent=emptyenv())
.env$new <- NULL
.cur <- .iniDf$name[i]
lapply(seq_along(lst),
function(j) {
if (!is.null(.env$new)) return(NULL)
.curLst <- lst[[j]]
.old <- .curLst[[4]]
if (.cur == .old) {
.env$new <- .curLst[[3]]
}
})
if (!is.null(.env$new)) return(.env$new)
return(.cur)
}, character(1), USE.NAMES=FALSE)
rxui$iniDf <- .iniDf
if (exists("sigma", rxui)) {
assign("sigma", .rxRenameAllMat(get("sigma", envir=rxui), lst), envir=rxui)
}
if (exists("thetaMat", rxui)) {
assign("thetaMat", .rxRenameAllMat(get("thetaMat", envir=rxui), lst), envir=rxui)
}
if (exists("meta", rxui)) {
.meta <- get("meta", rxui)
if (exists("sigma", .meta)) {
assign("sigma", .rxRenameAllMat(get("sigma", envir=.meta), lst), envir=.meta)
}
if (exists("thetaMat", .meta)) {
assign("thetaMat", .rxRenameAllMat(get("thetaMat", envir=.meta), lst), envir=.meta)
}
}
rxui$lstExpr <- lapply(seq_along(rxui$lstExpr),
function(i) {
.rxRenameRecursive(rxui$lstExpr[[i]], new=lst[[1]], old=lst[[2]])
.rxRenameRecursiveAll(rxui$lstExpr[[i]], lst=lst)
})
}

Expand Down Expand Up @@ -164,21 +245,29 @@ rxRename <- function(.data, ..., envir=parent.frame()) {
#' @rdname rxRename
#' @export
.rxRename <- function(.data, ..., envir=parent.frame()) {
.inCompress <- FALSE
if (inherits(.data, "rxUi") &&
inherits(.data, "raw")) {
.inCompress <- TRUE
}
rxui <- assertRxUi(.data)
if (inherits(rxui, "raw")) {
rxui <- rxUiDecompress(rxui)
}
.vars <- unique(c(rxui$mv0$state, rxui$mv0$params, rxui$mv0$lhs, rxui$predDf$var, rxui$predDf$cond, rxui$iniDf$name))
.modelLines <- .quoteCallInfoLines(match.call(expand.dots = TRUE)[-(1:2)], envir=envir)
.lst <- lapply(seq_along(.modelLines), function(i) {
.assertRenameErrorModelLine(.modelLines[[i]], .vars)
})
rxui <- .copyUi(rxui) # copy ui so effects do not affect original
lapply(seq_along(.lst), function(i) {
.rxRename1(rxui, .lst[[i]])
})
.rxRenameAll(rxui, .lst)
.ret <- rxui$fun()
if (inherits(.data, "rxUi")) {
.x <- rxUiDecompress(.data)
.ret <- .newModelAdjust(.ret, .x, rename=TRUE)
.ret <- rxUiCompress(.ret)
## .x <- rxUiDecompress(.data)
.ret <- .newModelAdjust(.ret, rxui, rename=TRUE)
if (.inCompress) {
.ret <- rxUiCompress(.ret)
}
.cls <- setdiff(class(.data), class(.ret))
if (length(.cls) > 0) {
class(.ret) <- c(.cls, class(.ret))
Expand Down Expand Up @@ -218,4 +307,4 @@ rxRename.default <- function(.data, ...) {
.lst <- as.list(match.call()[-1])
.lst$.data <- .data
do.call(.rxRename, c(.lst, list(envir=parent.frame(2))))
}
}
4 changes: 3 additions & 1 deletion _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ navbar:
- text: "Getting started"
- text: "rxode2 mini language syntax"
href: articles/rxode2-syntax.html
- text: "rxode2 with piping ie %>%"
- text: "rxode2 model modification %>%"
href: articles/Modifying-Models.html
- text: "rxode2 pipeline ie %>%"
href: articles/rxode2-pipeline.html
- text: "Speeding up rxode2 ODE solving"
href: articles/rxode2-speed.html
Expand Down
3 changes: 2 additions & 1 deletion man/reexports.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading