R/007_utilities_performance_utils.R

Defines functions compute_once

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/utilities/performance_utils.R
#####

## CVXPY SOURCE: utilities/performance_utils.py
##
## CVXPY caches instance members with two decorators:
##
##   @perf.compute_once          performance_utils.py lines 48-87
##       cache = self.__dict__[func.__name__ + '__cache__']
##       key = _cache_key(args, kwargs)
##           if scopes.dpp_scope_active():
##               key = ('__dpp_scope_active__',) + key
##           if scopes.quad_form_dpp_scope_active():
##               key = ('__quad_form_dpp_scope_active__',) + key
##
##   @pu.lazyprop                performance_utils.py lines 26-45
##       attr_name = '_lazy' + ('_dpp' | '') + ('_qfdpp' | '') + '_' + name
##
## Both key EVERY cached answer on the active DPP scopes, whether or not the
## member's answer can depend on them. CVXR hand-ported those decorators as one
## cache_get/cache_set pair per member, and five of the pairs chose a plain key
## and so answered whichever scope queried first (fixed one by one in
## 1.9.2.9125, ADR D_PORT.4). This file is the decorator: ONE helper, and every
## member cache in rsrc_tree goes through it, so no site chooses a key style.
## scripts/audit_completeness.py fails on a raw cache_get/cache_set outside it.
##
## R has no decorators; the member body is a named function `.class_member`
## and the S7 method is `compute_once(x, "member", .class_member)`. No-argument
## members only (every CVXPY compute_once member CVXR caches takes none), so
## lazyprop and compute_once collapse to the same helper.
##
## CVXPY has a THIRD idiom beside the two decorators: a plain instance
## attribute set once, `if self._x is None: self._x = ...` (constant.py
## 124-134 `_cached_is_pos`, 222-246 `_nonneg`/`_nonpos`/`_imag`,
## `_symm`/`_herm`, `_skew_symm`, 248-290 `_psd_test`/`_nsd_test`). Those
## answers depend on the stored value only, so CVXPY keeps ONE copy per
## instance; the scope-keyed decorator, where present, wraps the stored test.
## `scoped = FALSE` is that idiom. 1.9.2.9126 routed the Constant value tests
## through the scoped key and so ran the PSD eigenvalue test, the Hermitian
## check and the sign scan once per scope (`qp` mem_alloc +16%,
## notes/benchmark_results.md "Regression B"); 9144 restores CVXPY's split.
## The audit gate fails `scoped = FALSE` on a member CVXPY decorates.

#' Cache a member's result per (object, member, DPP scope, quad_form_dpp scope)
#'
#' Mirror of CVXPY's `compute_once` / `lazyprop`. The key is `.dpp_key(name)`:
#' the plain name outside any scope, `_dpp` / `_qfdpp` / `_dpp_qfdpp` variants
#' inside one, so an answer computed under a scope never serves a query made
#' outside it (or vice versa). `fn(x)` is evaluated on a miss only. `NULL` and
#' `FALSE` are real results and are cached.
#'
#' @param x An object carrying a `.cache` environment (Expression, Problem,
#'   Constraint, Canonical).
#' @param name The member name; the base cache key.
#' @param fn A function of `x` computing the member.
#' @param scoped `TRUE` (the decorators): key on the active scopes. `FALSE`
#'   (a CVXPY instance attribute set once): the plain name, one answer per
#'   object whatever the scope. Only for members whose answer cannot depend
#'   on the scope, i.e. computed from the stored value alone.
#' @returns The cached or freshly computed result.
#' @noRd
compute_once <- function(x, name, fn, scoped = TRUE) {
  key <- if (scoped) .dpp_key(name) else name
  cached <- cache_get(x, key)
  if (!cache_miss(cached)) return(cached)
  result <- fn(x)
  cache_set(x, key, result)
  result
}

Try the CVXR package in your browser

Any scripts or data that you put into this service are public.

CVXR documentation built on Oct. 19, 2026, 5:07 p.m.