|
| 1 | +#' Create a definition of derived quantities evaluated in R. |
| 2 | +#' |
| 3 | +#' When the expression contains non-library functions/objects, and parallel processing |
| 4 | +#' is enabled, those must be |
| 5 | +#' named in the `.globals` parameter (hopefully we'll be able to detect those |
| 6 | +#' automatically in the future). Note that [recompute_SBC_statistics()] currently |
| 7 | +#' does not use parallel processing, so `.globals` don't need to be set. |
| 8 | +#' |
| 9 | +#' @param ... named expressions representing the quantitites |
| 10 | +#' @param .globals A list of names of objects that are defined |
| 11 | +#' in the global environment and need to present for the gen. quants. to evaluate. |
| 12 | +#' It is added to the `globals` argument to [future::future()], to make those |
| 13 | +#' objects available on all workers. |
| 14 | +#' @examples |
| 15 | +#'# Derived quantity computing the total log likelihood of a normal distribution |
| 16 | +#'# with known sd = 1 |
| 17 | +#'normal_lpdf <- function(y, mu, sigma) { |
| 18 | +#' sum(dnorm(y, mean = mu, sd = sigma, log = TRUE)) |
| 19 | +#'} |
| 20 | +#' |
| 21 | +#'# Note the use of .globals to make the normal_lpdf function available |
| 22 | +#'# within the expression |
| 23 | +#'log_lik_dq <- derived_quantities(log_lik = normal_lpdf(y, mu, 1), |
| 24 | +#' .globals = "normal_lpdf" ) |
| 25 | +#' |
| 26 | +#' @export |
| 27 | +derived_quantities <- function(..., .globals = list()) { |
| 28 | + structure(rlang::enquos(..., .named = TRUE), |
| 29 | + class = "SBC_derived_quantities", |
| 30 | + globals = .globals |
| 31 | + ) |
| 32 | +} |
| 33 | + |
| 34 | +#' @title Validate a definition of derived quantities evaluated in R. |
| 35 | +#' @export |
| 36 | +validate_derived_quantities <- function(x) { |
| 37 | + # Backwards compatibility |
| 38 | + if(inherits(x, "SBC_generated_quantities")) { |
| 39 | + class(x) <- "SBC_derived_quantities" |
| 40 | + } |
| 41 | + stopifnot(inherits(x, "SBC_derived_quantities")) |
| 42 | + invisible(x) |
| 43 | +} |
| 44 | + |
| 45 | +#' @title Combine two lists of derived quantities |
| 46 | +#' @export |
| 47 | +bind_derived_quantities <- function(dq1, dq2) { |
| 48 | + validate_derived_quantities(dq1) |
| 49 | + validate_derived_quantities(dq2) |
| 50 | + structure(c(dq1, dq2), |
| 51 | + class = "SBC_derived_quantities", |
| 52 | + globals = bind_globals(attr(dq1, "globals"), attr(dq2, "globals"))) |
| 53 | +} |
| 54 | + |
| 55 | +#'@title Compute derived quantities based on given data and posterior draws. |
| 56 | +#'@param gen_quants Deprecated, use `dquants` |
| 57 | +#'@export |
| 58 | +compute_dquants <- function(draws, generated, dquants, gen_quants = NULL) { |
| 59 | + if(!is.null(gen_quants)) { |
| 60 | + warning("gen_quants argument is deprecated, use dquants") |
| 61 | + if(rlang::is_missing(dquants)) { |
| 62 | + dquants <- gen_quants |
| 63 | + } |
| 64 | + } |
| 65 | + dquants <- validate_derived_quantities(dquants) |
| 66 | + draws_rv <- posterior::as_draws_rvars(draws) |
| 67 | + |
| 68 | + draws_env <- list2env(draws_rv) |
| 69 | + if(!is.null(generated)) { |
| 70 | + if(!is.list(generated)) { |
| 71 | + stop("compute_dquants assumes that generated is a list, but this is not the case") |
| 72 | + } |
| 73 | + generated_env <- list2env(generated, parent = draws_env) |
| 74 | + |
| 75 | + data_mask <- rlang::new_data_mask(bottom = generated_env, top = draws_env) |
| 76 | + } else { |
| 77 | + data_mask <- rlang::new_data_mask(bottom = draws_env) |
| 78 | + } |
| 79 | + |
| 80 | + eval_func <- function(dq) { |
| 81 | + # Wrap the expression in `rdo` which will mostly do what we need |
| 82 | + # all the tricks are just to have the correct environment when we need it |
| 83 | + wrapped_dq <- rlang::new_quosure(rlang::expr(posterior::rdo(!!rlang::get_expr(dq))), rlang::get_env(dq)) |
| 84 | + rlang::eval_tidy(wrapped_dq, data = data_mask) |
| 85 | + } |
| 86 | + rvars <- lapply(dquants, FUN = eval_func) |
| 87 | + do.call(posterior::draws_rvars, rvars) |
| 88 | +} |
| 89 | + |
| 90 | + |
| 91 | + |
| 92 | +#' @title Create a definition of derived quantities evaluated in R. |
| 93 | +#' @description Delegates directly to `derived_quantities()`. |
| 94 | +#' |
| 95 | +#' @name generated_quantities-deprecated |
| 96 | +#' @seealso \code{\link{SBC-deprecated}} |
| 97 | +#' @keywords internal |
| 98 | +NULL |
| 99 | + |
| 100 | +#' @rdname SBC-deprecated |
| 101 | +#' @section \code{generated_quantities}: |
| 102 | +#' Instead of \code{generated_quantities}, use \code{\link{derived_quantities}}. |
| 103 | +#' |
| 104 | +#' @export |
| 105 | +generated_quantities <- function(...) { |
| 106 | + warning("generated_quantities() is deprecated, use derived_quantities instead.") |
| 107 | + derived_quantities(...) |
| 108 | +} |
| 109 | + |
| 110 | +#' @title Validate a definition of derived quantities evaluated in R. |
| 111 | +#' @description Delegates directly to `validate_derived_quantities()`. |
| 112 | +#' |
| 113 | +#' @name generated_quantities-deprecated |
| 114 | +#' @seealso \code{\link{SBC-deprecated}} |
| 115 | +#' @keywords internal |
| 116 | +NULL |
| 117 | + |
| 118 | +#' @rdname SBC-deprecated |
| 119 | +#' @section \code{validate_generated_quantities}: |
| 120 | +#' Instead of \code{validate_generated_quantities}, use \code{\link{validate_derived_quantities}}. |
| 121 | +#' |
| 122 | +#' @export |
| 123 | +validate_generated_quantities <- function(...) { |
| 124 | + warning("generated_quantities() is deprecated, use validate_derived_quantities instead.") |
| 125 | + validate_derived_quantities(...) |
| 126 | +} |
| 127 | + |
| 128 | +#' @title Combine two lists of derived quantities |
| 129 | +#' @description Delegates directly to `bind_derived_quantities()`. |
| 130 | +#' |
| 131 | +#' @name bind_generated_quantities-deprecated |
| 132 | +#' @seealso \code{\link{SBC-deprecated}} |
| 133 | +#' @keywords internal |
| 134 | +NULL |
| 135 | + |
| 136 | +#' @rdname SBC-deprecated |
| 137 | +#' @section \code{bind_generated_quantities}: |
| 138 | +#' Instead of \code{bind_generated_quantities}, use \code{\link{bind_derived_quantities}}. |
| 139 | +#' |
| 140 | +#' @export |
| 141 | +bind_generated_quantities <- function(...) { |
| 142 | + warning("bind_generated_quantities() is deprecated, use bind_derived_quantities instead.") |
| 143 | + bind_derived_quantities(...) |
| 144 | +} |
| 145 | + |
| 146 | +#'@title Compute derived quantities based on given data and posterior draws. |
| 147 | +#' @description Delegates directly to `compute_dquants()`. |
| 148 | +#' |
| 149 | +#' @name compute_gen_quants-deprecated |
| 150 | +#' @seealso \code{\link{SBC-deprecated}} |
| 151 | +#' @keywords internal |
| 152 | +NULL |
| 153 | + |
| 154 | +#' @rdname SBC-deprecated |
| 155 | +#' @section \code{compute_gen_quants}: |
| 156 | +#' Instead of \code{compute_gen_quants}, use \code{\link{compute_dquants}}. |
| 157 | +#' |
| 158 | +#' @export |
| 159 | +compute_gen_quants <- function(...) { |
| 160 | + warning("compute_gen_quants() is deprecated, use compute_dquants() instead.") |
| 161 | + compute_dquants(...) |
| 162 | +} |
0 commit comments