R/130_constraints_constraint.R

Defines functions dual_value constr_expr

Documented in dual_value

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/constraints/constraint.R
#####

## CVXPY SOURCE: constraints/constraint.py
## Constraint -- base class for all constraints
##
## Constraints inherit from Canonical (NOT Expression).
## They have a shape, dual variables, DCP checking, and residual computation.


Constraint <- new_class("Constraint", parent = Canonical, package = "CVXR",
  properties = list(
    dual_variables = new_property(class = class_list, default = list()),
    shape = new_property(class = class_integer, default = c(1L, 1L)),
    .label = new_property(class = class_character, default = "")
  ),
  constructor = function(args, constr_id = NULL) {
    if (FALSE) new_object(S7_object())  ## S7 static-check guard
    if (is.null(constr_id)) constr_id <- next_expr_id()
    shape <- args[[1L]]@shape
    dvars <- lapply(args, function(a) Variable(a@shape))
    .fast_new(Constraint, S7_object(),
      id    = as.integer(constr_id),
      .cache = new.env(parent = emptyenv()),
      args  = args,
      dual_variables = dvars,
      shape = shape,
      .label = ""
    )
  }
)

# -- expr: convenience accessor for single-arg constraints ---------
## CVXPY SOURCE: utilities/canonical.py lines 41-45
## Returns args[[1]] when exactly one arg; errors otherwise.
## Equality/Inequality override via constr_expr() to return ._expr.

constr_expr <- function(x) {
  if (length(x@args) != 1L) {
    cli_abort("{.fn constr_expr} is ambiguous, there should be only one argument.")
  }
  x@args[[1L]]
}

# -- get_data ------------------------------------------------------
## CVXPY SOURCE: constraint.py line 276-279

method(get_data, Constraint) <- function(x) list(x@id)

# -- value: check if constraint is satisfied -----------------------
## CVXPY SOURCE: constraint.py lines 240-264
## Returns TRUE if all residuals <= tolerance.

method(value, Constraint) <- function(x) {
  res <- residual(x)
  if (is.null(res)) {
    cli_abort("Cannot compute the value of a constraint whose expression has no value.")
  }
  all(res <= 1e-8)
}

# -- violation: base returns residual ------------------------------
## CVXPY SOURCE: constraint.py lines 209-238
## Base class returns residual directly. NonPos/NonNeg override with L2 norm.

method(violation, Constraint) <- function(x) {
  res <- residual(x)
  if (is.null(res)) {
    cli_abort("Cannot compute the violation of a constraint whose expression has no value.")
  }
  res
}

# -- is_real / is_complex / is_imag --------------------------------
## CVXPY SOURCE: constraint.py lines 151-164

method(is_real, Constraint) <- function(x) !is_complex(x)

method(is_complex, Constraint) <- function(x) {
  .any_args(x, is_complex)
}

method(is_imag, Constraint) <- function(x) {
  .all_args(x, is_imag)
}

#' Get the Dual Value of a Constraint
#'
#' Returns the dual variable value(s) associated with a constraint
#' after solving. Returns \code{NULL} before the problem is solved.
#'
#' @param x A \code{Constraint} object.
#' @returns A numeric matrix (single dual variable) or a list of
#'   numeric matrices (multiple dual variables), or \code{NULL}.
#' @export
dual_value <- function(x) {
  if (!.s7_is(x, Constraint)) {
    cli_abort("{.fn dual_value} requires a {.cls Constraint} object.")
  }
  vals <- lapply(x@dual_variables, value)
  if (length(vals) == 1L) vals[[1L]] else vals
}

# -- save_dual_value -----------------------------------------------
## CVXPY SOURCE: constraint.py lines 311-316

method(save_dual_value, Constraint) <- function(x, val) {
  ## Use save_leaf_value (no validation) -- dual values from solver
  ## may arrive as flat vectors needing no reshape at this level
  save_leaf_value(x@dual_variables[[1L]], val)
  invisible(x)
}

# -- constr_size --------------------------------------------------
## CVXPY SOURCE: constraint.py lines 147-149 -- size property

method(constr_size, Constraint) <- function(x) {
  prod(x@args[[1L]]@shape)
}

# -- is_dgp -------------------------------------------------------
## CVXPY SOURCE: constraint.py lines 178-186 -- abstract, default FALSE

method(is_dgp, Constraint) <- function(x) FALSE

# -- is_dqcp ------------------------------------------------------
## CVXPY SOURCE: constraint.py -- no base class default, add fallback
## Default: is_dcp() (most cone constraints are DQCP iff DCP)

method(is_dqcp, Constraint) <- function(x) is_dcp(x)

# -- is_dpp -------------------------------------------------------
## CVXPY SOURCE: constraint.py lines 188-194

method(is_dpp, Constraint) <- function(x, context = "dcp") {
  base_ok <- if (identical(tolower(context), "dgp")) with_dpp_scope(is_dgp(x))
             else with_dpp_scope(is_dcp(x))
  if (!base_ok) return(FALSE)
  for (arg in x@args) {
    if (!is_dpp(arg, context)) return(FALSE)
  }
  TRUE
}

# -- print ---------------------------------------------------------

method(print, Constraint) <- function(x, ...) {
  cat(expr_name(x), "\n")
  invisible(x)
}

## Constraint-side set_label.  Method on the generic declared in
## zzz_R_specific/generics.R; behaves exactly like the original
## (sets `@.label`) so existing callers / visualize() keep working.
## `value = NULL` clears the label (mirrors Expression semantics).
method(set_label, Constraint) <- function(x, value) {
  x@.label <- if (is.null(value)) "" else as.character(value)[[1L]]
  invisible(x)
}

method(label, Constraint) <- function(x) {
  if (nzchar(x@.label)) x@.label else NULL
}

method(`label<-`, Constraint) <- function(x, value) {
  x@.label <- if (is.null(value)) "" else as.character(value)[[1L]]
  invisible(x)
}

Try the CVXR package in your browser

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

CVXR documentation built on Aug. 24, 2026, 9:10 a.m.