R/021_utilities_canonical.R

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

## CVXPY SOURCE: utilities/canonical.py
## Canonical -- base class for all canonicalizable objects


Canonical <- new_class("Canonical", package = "CVXR",
  properties = list(
    id     = new_property(class = class_integer),
    .cache = new_property(class = class_any,
                          default = quote(new.env(parent = emptyenv()))),
    args   = new_property(class = class_list, default = list())
  ),
  constructor = function(id = NULL, args = list()) {
    if (is.null(id)) id <- next_expr_id()
    new_object(S7_object(), id = as.integer(id),
               .cache = new.env(parent = emptyenv()), args = args)
  }
)

# -- Default methods on Canonical --------------------------------------

## variables(): recurse over args, dedup by id
## CVXPY SOURCE: canonical.py line 58-62
method(variables, Canonical) <- function(x) {
  unique_list(unlist(lapply(x@args, variables), recursive = FALSE))
}

## parameters(): recurse over args, dedup by id
## CVXPY SOURCE: canonical.py line 64-68
method(parameters, Canonical) <- function(x) {
  unique_list(unlist(lapply(x@args, parameters), recursive = FALSE))
}

## constants(): recurse over args, dedup by id
## CVXPY SOURCE: canonical.py line 70-74
method(constants, Canonical) <- function(x) {
  unique_list(unlist(lapply(x@args, constants), recursive = FALSE))
}

## atoms(): recurse over args, dedup by id
## CVXPY SOURCE: canonical.py line 163-171
method(atoms, Canonical) <- function(x) {
  unique_list(unlist(lapply(x@args, atoms), recursive = FALSE))
}

## get_data(): default returns NULL
## CVXPY SOURCE: canonical.py line 154-161
method(get_data, Canonical) <- function(x) NULL

## canonicalize(): default errors -- subclasses must implement
method(canonicalize, Canonical) <- function(x) {
  cli_abort("Class {.cls {class(x)[[1L]]}} must implement {.fn canonicalize}.")
}

## canonical_form: lazily-cached wrapper around canonicalize()
## CVXPY SOURCE: canonical.py lines 47-54 (@lazyprop)
method(canonical_form, Canonical) <- function(x) {
  cached <- cache_get(x, "canonical_form")
  if (!cache_miss(cached)) return(cached)
  result <- canonicalize(x)
  cache_set(x, "canonical_form", result)
  result
}

## copy(): shallow copy of a node (reconstruct from args + get_data)
## CVXPY SOURCE: canonical.py lines 86-112
method(expr_copy, Canonical) <- function(x, args = NULL, id_objects = NULL) {
  if (is.null(id_objects)) id_objects <- new.env(hash = TRUE, parent = emptyenv())
  key <- as.character(x@id)
  if (exists(key, envir = id_objects, inherits = FALSE)) {
    return(get(key, envir = id_objects, inherits = FALSE))
  }
  ## For Leaf nodes (no args), return self -- they are immutable
  if (length(x@args) == 0L && (is.null(args) || length(args) == 0L)) return(x)
  if (is.null(args)) args <- x@args
  data <- get_data(x)
  ## Reconstruct via the class constructor
  cls <- S7_class(x)
  if (!is.null(data)) {
    result <- do.call(cls, c(args, data))
  } else {
    result <- do.call(cls, args)
  }
  assign(key, result, envir = id_objects)
  result
}

## tree_copy(): deep copy of the entire expression tree
## CVXPY SOURCE: canonical.py lines 76-84
method(tree_copy, Canonical) <- function(x, id_objects = NULL) {
  if (is.null(id_objects)) id_objects <- new.env(hash = TRUE, parent = emptyenv())
  new_args <- lapply(x@args, function(arg) {
    if (is.list(arg)) {
      lapply(arg, function(elem) tree_copy(elem, id_objects))
    } else {
      tree_copy(arg, id_objects)
    }
  })
  expr_copy(x, args = new_args, id_objects = id_objects)
}

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.