R/121_constraints_constraint.R

Defines functions set_label dual_value constr_expr

Documented in dual_value set_label

#####
## 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 (is.null(constr_id)) constr_id <- next_expr_id()
    shape <- args[[1L]]@shape
    dvars <- lapply(args, function(a) Variable(a@shape))
    new_object(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_inherits(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) {
  with_dpp_scope(is_dcp(x))
}

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

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

#' Set a Label on a Constraint
#'
#' Attaches a human-readable label to a constraint for use in
#' visualizations and pretty-printing. Labels are visualization-only
#' and never affect the solver pipeline.
#'
#' Because R uses copy-on-modify semantics, you must either assign the
#' result back or use \code{set_label} fluently when building constraint
#' lists.
#'
#' @param constraint A \code{Constraint} object.
#' @param label A character string label.
#' @returns The modified constraint (invisibly).
#'
#' @examples
#' \dontrun{
#' x <- Variable(3, name = "x")
#'
#' # Assign back
#' con <- (x >= 0)
#' con <- set_label(con, "non-negativity")
#'
#' # Fluent use in constraint lists
#' constraints <- list(
#'   set_label(x >= 1, "lower bound"),
#'   set_label(sum_entries(x) <= 10, "budget")
#' )
#' }
#'
#' @export
set_label <- function(constraint, label) {
  if (!S7_inherits(constraint, Constraint)) {
    cli_abort("{.fn set_label} requires a {.cls Constraint} object.")
  }
  constraint@.label <- as.character(label)
  invisible(constraint)
}

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.