R/135_reductions_eval_params.R

Defines functions .replace_params_with_consts

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/eval_params.R
#####

## CVXPY SOURCE: reductions/eval_params.py
## EvalParams -- replaces symbolic Parameters with their current Constant values
##
## This is the non-DPP path: every Parameter is substituted with a Constant
## before the rest of the solving chain runs. The problem is fully
## re-canonicalized each time.  When DPP support is added later, EvalParams
## becomes the fallback for non-DPP-compliant problems.

# -- Helper: replace Parameters with Constants in an expression tree --

## Walks the expression tree.  Parameter nodes are replaced with
## Constant(value(param)).  Expressions with no parameters are
## returned as-is (short-circuit).
.replace_params_with_consts <- function(expr) {
  ## List case (e.g., list of constraint args)
  if (is.list(expr) && !S7_inherits(expr, Canonical)) {
    return(lapply(expr, .replace_params_with_consts))
  }
  ## Short-circuit: no parameters anywhere below

  if (length(parameters(expr)) == 0L) return(expr)

  ## Base case: this IS a Parameter
  if (S7_inherits(expr, Parameter)) {
    v <- value(expr)
    if (is.null(v)) {
      cli_abort(c(
        "Problem contains an unspecified parameter.",
        "i" = "Set {.code value({expr_name(expr)}) <- <value>} before solving."
      ))
    }
    return(Constant(v))
  }

  ## Recursive case: rebuild node with substituted children

  new_args <- lapply(expr@args, .replace_params_with_consts)
  ## If nothing changed, return original (avoids unnecessary copy)
  changed <- !identical(
    vapply(new_args, function(a) a@id, integer(1L)),
    vapply(expr@args, function(a) a@id, integer(1L))
  )
  if (!changed) return(expr)

  expr_copy(expr, args = new_args)
}

# -- EvalParams reduction class ---------------------------------------
## CVXPY SOURCE: eval_params.py lines 24-78

EvalParams <- new_class("EvalParams", parent = Reduction, package = "CVXR",
  constructor = function() {
    new_object(S7_object(),
      .cache = new.env(parent = emptyenv())
    )
  }
)

## accepts: always TRUE -- any problem can have its parameters evaluated
method(reduction_accepts, EvalParams) <- function(x, problem, ...) TRUE

## apply: substitute Parameters -> Constants in objective and constraints
## CVXPY SOURCE: eval_params.py lines 30-73
method(reduction_apply, EvalParams) <- function(x, problem, ...) {
  ## -- Objective --------------------------------------------------
  obj <- problem@objective
  if (length(parameters(obj)) > 0L) {
    new_obj_expr <- .replace_params_with_consts(obj@args[[1L]])
    obj <- S7_class(obj)(new_obj_expr)
  }

  ## -- Constraints ------------------------------------------------
  new_constraints <- vector("list", length(problem@constraints))
  for (i in seq_along(problem@constraints)) {
    con <- problem@constraints[[i]]
    if (length(parameters(con)) == 0L) {
      new_constraints[[i]] <- con
      next
    }
    new_args <- lapply(con@args, .replace_params_with_consts)
    ## Check if anything actually changed
    changed <- !identical(
      vapply(new_args, function(a) a@id, integer(1L)),
      vapply(con@args, function(a) a@id, integer(1L))
    )
    if (!changed) {
      new_constraints[[i]] <- con
    } else {
      ## Reconstruct constraint via get_data + constructor (same as expr_copy)
      data <- get_data(con)
      cls <- S7_class(con)
      if (!is.null(data)) {
        new_constraints[[i]] <- do.call(cls, c(new_args, data))
      } else {
        new_constraints[[i]] <- do.call(cls, new_args)
      }
    }
  }

  list(Problem(obj, new_constraints), list())
}

## invert: pass-through -- parameter evaluation doesn't change the solution
## CVXPY SOURCE: eval_params.py lines 75-78
method(reduction_invert, EvalParams) <- function(x, solution, inverse_data, ...) {
  solution
}

Try the CVXR package in your browser

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

CVXR documentation built on March 6, 2026, 9:10 a.m.