Nothing
#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/problems/objective.R
#####
## CVXPY SOURCE: problems/objective.py
## Objective, Minimize, Maximize -- optimization objective wrappers
##
## CVXPY 1.9 parity notes:
## - DNLP objective predicates mirror objective.py:159-163 and 236-240:
## Minimize requires a linearizable-convex target; Maximize requires a
## linearizable-concave target.
# -- scalar_value: extract scalar from 1x1 matrix ---------------------
## CVXPY SOURCE: interface/matrix_utilities.py::scalar_value
scalar_value <- function(v) {
if (is.null(v)) return(NULL)
if (is.numeric(v) && length(v) == 1L) return(as.double(v))
if (is.matrix(v) || inherits(v, "Matrix")) {
if (prod(dim(v)) == 1L) return(as.double(v[1L, 1L]))
}
as.double(v[1L])
}
# -- Objective base class ---------------------------------------------
## CVXPY SOURCE: objective.py lines 25-116
Objective <- new_class("Objective", parent = Canonical, package = "CVXR",
properties = list(
.name = new_property(class = class_character, default = "objective")
),
constructor = function(expr) {
if (FALSE) new_object(S7_object()) ## S7 static-check guard
expr <- as_expr(expr)
## Validate scalar
## CVXPY SOURCE: objective.py lines 46-49
if (!expr_is_scalar(expr)) {
cli_abort("The {.val objective} objective must resolve to a scalar.")
}
if (!is_real(expr)) {
cli_abort("The {.val objective} objective must be real valued.")
}
.fast_new(Objective, S7_object(),
id = next_expr_id(),
.cache = new.env(parent = emptyenv()),
args = list(expr),
.name = "objective"
)
}
)
# -- Objective value --------------------------------------------------
## CVXPY SOURCE: objective.py lines 97-105
method(value, Objective) <- function(x) {
v <- value(x@args[[1L]])
if (is.null(v)) return(NULL)
scalar_value(v)
}
# -- Objective print --------------------------------------------------
method(print, Objective) <- function(x, ...) {
cat(sprintf("%s %s\n", x@.name, expr_name(x@args[[1L]])))
invisible(x)
}
# -- Objective is_quadratic / is_qpwa --------------------------------
## CVXPY SOURCE: objective.py lines 107-115
method(is_quadratic, Objective) <- function(x) is_quadratic(x@args[[1L]])
method(is_qpwa, Objective) <- function(x) is_qpwa(x@args[[1L]])
# -- Objective is_dcp default -----------------------------------------
method(is_dcp, Objective) <- function(x) FALSE
# -- Minimize ---------------------------------------------------------
## CVXPY SOURCE: objective.py lines 118-186
#' Create a Minimization Objective
#'
#' Specifies that the objective expression should be minimized. The expression
#' must be convex and scalar for a DCP-compliant problem.
#'
#' @param expr A CVXR expression or numeric value to minimize.
#' @returns A \code{Minimize} object.
#'
#' @examples
#' x <- Variable()
#' obj <- Minimize(x^2 + 1)
#'
#' @seealso \code{\link{Maximize}}, \code{\link{Problem}}
#' @export
Minimize <- new_class("Minimize", parent = Objective, package = "CVXR",
constructor = function(expr) {
if (FALSE) new_object(S7_object()) ## S7 static-check guard
expr <- as_expr(expr)
if (!expr_is_scalar(expr)) {
cli_abort("The {.val minimize} objective must resolve to a scalar.")
}
if (!is_real(expr)) {
cli_abort("The {.val minimize} objective must be real valued.")
}
.fast_new(Minimize, S7_object(),
id = next_expr_id(),
.cache = new.env(parent = emptyenv()),
args = list(expr),
.name = "minimize"
)
}
)
## is_dcp: the objective expression must be convex
## CVXPY SOURCE: objective.py lines 151-157
method(is_dcp, Minimize) <- function(x) is_convex(x@args[[1L]])
## is_dqcp: the objective expression must be quasiconvex
## CVXPY SOURCE: objective.py lines 176-179
method(is_dqcp, Minimize) <- function(x) is_quasiconvex(x@args[[1L]])
## is_dnlp: the objective expression must be linearizable-convex
## CVXPY SOURCE: objective.py lines 159-163
method(is_dnlp, Minimize) <- function(x) is_linearizable_convex(x@args[[1L]])
## is_dgp: the objective expression must be log-log convex
## CVXPY SOURCE: objective.py lines 159-165
method(is_dgp, Minimize) <- function(x) is_log_log_convex(x@args[[1L]])
## is_dpp: check DPP compliance within DPP scope
## CVXPY SOURCE: objective.py lines 167-174
method(is_dpp, Minimize) <- function(x, context = "dcp") {
.check_dpp_context(context)
arg <- x@args[[1L]]
curv <- if (identical(tolower(context), "dgp")) with_dpp_scope(is_log_log_convex(arg))
else with_dpp_scope(is_convex(arg))
curv && is_dpp(arg, context)
}
## canonicalize: pass through the expression's canonical form
## CVXPY SOURCE: objective.py lines 146-149
method(canonicalize, Minimize) <- function(x) canonical_form(x@args[[1L]])
## print
method(print, Minimize) <- function(x, ...) {
cat(sprintf("minimize %s\n", expr_name(x@args[[1L]])))
invisible(x)
}
# -- Maximize ---------------------------------------------------------
## CVXPY SOURCE: objective.py lines 188-257
#' Create a Maximization Objective
#'
#' Specifies that the objective expression should be maximized. The expression
#' must be concave and scalar for a DCP-compliant problem.
#'
#' @param expr A CVXR expression or numeric value to maximize.
#' @returns A \code{Maximize} object.
#'
#' @examples
#' x <- Variable()
#' obj <- Maximize(-x^2 + 1)
#'
#' @seealso \code{\link{Minimize}}, \code{\link{Problem}}
#' @export
Maximize <- new_class("Maximize", parent = Objective, package = "CVXR",
constructor = function(expr) {
if (FALSE) new_object(S7_object()) ## S7 static-check guard
expr <- as_expr(expr)
if (!expr_is_scalar(expr)) {
cli_abort("The {.val maximize} objective must resolve to a scalar.")
}
if (!is_real(expr)) {
cli_abort("The {.val maximize} objective must be real valued.")
}
.fast_new(Maximize, S7_object(),
id = next_expr_id(),
.cache = new.env(parent = emptyenv()),
args = list(expr),
.name = "maximize"
)
}
)
## is_dcp: the objective expression must be concave
## CVXPY SOURCE: objective.py lines 222-228
method(is_dcp, Maximize) <- function(x) is_concave(x@args[[1L]])
## is_dqcp: the objective expression must be quasiconcave
## CVXPY SOURCE: objective.py lines 247-250
method(is_dqcp, Maximize) <- function(x) is_quasiconcave(x@args[[1L]])
## is_dnlp: the objective expression must be linearizable-concave
## CVXPY SOURCE: objective.py lines 236-240
method(is_dnlp, Maximize) <- function(x) is_linearizable_concave(x@args[[1L]])
## is_dgp: the objective expression must be log-log concave
## CVXPY SOURCE: objective.py lines 230-236
method(is_dgp, Maximize) <- function(x) is_log_log_concave(x@args[[1L]])
## is_dpp: check DPP compliance within DPP scope
## CVXPY SOURCE: objective.py lines 238-245
method(is_dpp, Maximize) <- function(x, context = "dcp") {
.check_dpp_context(context)
arg <- x@args[[1L]]
curv <- if (identical(tolower(context), "dgp")) with_dpp_scope(is_log_log_concave(arg))
else with_dpp_scope(is_concave(arg))
curv && is_dpp(arg, context)
}
## canonicalize: negate the expression's canonical form
## CVXPY SOURCE: objective.py lines 216-220
method(canonicalize, Maximize) <- function(x) {
result <- canonical_form(x@args[[1L]])
obj <- result[[1L]]
constraints <- result[[2L]]
list(neg_expr_linop(obj), constraints)
}
## print
method(print, Maximize) <- function(x, ...) {
cat(sprintf("maximize %s\n", expr_name(x@args[[1L]])))
invisible(x)
}
# -- Objective arithmetic ---------------------------------------------
## CVXPY SOURCE: objective.py lines 61-105 (Objective.__add__, __mul__, etc.)
## Reject an unrecognized DPP context.
## CVXPY SOURCE: objective.py:173-181 / 250-258 -- both Minimize.is_dpp and
## Maximize.is_dpp raise ValueError("Unsupported context ", context) for
## anything other than 'dcp'/'dgp'. CVXR previously fell through to the dcp
## branch for ANY non-"dgp" string, so a typo silently answered the wrong
## question instead of erroring.
.check_dpp_context <- function(context) {
if (!is.character(context) || length(context) != 1L ||
!(tolower(context) %in% c("dcp", "dgp"))) {
cli_abort(c(
"Unsupported DPP context {.val {context}}.",
"i" = "Use {.val dcp} or {.val dgp}."
))
}
invisible(TRUE)
}
## Negate: -Minimize(f) -> Maximize(-f), -Maximize(f) -> Minimize(-f)
## CVXPY SOURCE: objective.py Minimize.__neg__ / Maximize.__neg__
.negate_objective <- function(obj) {
expr <- obj@args[[1L]]
if (.s7_is(obj, Minimize)) Maximize(-expr) else Minimize(-expr)
}
## Add: both must be same type (Minimize+Minimize or Maximize+Maximize)
## CVXPY SOURCE: objective.py Minimize.__add__ / Maximize.__add__
.add_objectives <- function(o1, o2) {
if (!.s7_is(o2, Objective))
cli_abort("Cannot add {.cls {class(o2)[[1L]]}} to an objective.")
e1 <- o1@args[[1L]]
e2 <- o2@args[[1L]]
if (.s7_is(o1, Minimize) && .s7_is(o2, Minimize)) {
Minimize(e1 + e2)
} else if (.s7_is(o1, Maximize) && .s7_is(o2, Maximize)) {
Maximize(e1 + e2)
} else {
cli_abort("Cannot add {.cls Minimize} and {.cls Maximize} (violates DCP).")
}
}
## Subtract: o1 - o2 = o1 + (-o2)
.sub_objectives <- function(o1, o2) {
.add_objectives(o1, .negate_objective(o2))
}
## Multiply by scalar: sign flip reverses direction
## CVXPY SOURCE: objective.py Objective.__mul__
.mul_objective <- function(obj, scalar) {
if (!is.numeric(scalar) || length(scalar) != 1L)
cli_abort("Objective can only be multiplied by a numeric scalar.")
expr <- obj@args[[1L]]
## If (Maximize && negative) or (Minimize && negative), flip direction
if ((.s7_is(obj, Maximize)) == (scalar < 0)) {
Minimize(expr * scalar)
} else {
Maximize(expr * scalar)
}
}
## Divide by scalar
.div_objective <- function(obj, scalar) {
if (!is.numeric(scalar) || length(scalar) != 1L)
cli_abort("Objective can only be divided by a numeric scalar.")
.mul_objective(obj, 1.0 / scalar)
}
## -- Ops dispatch for Objective ---------------------------------------
## CVXPY SOURCE: objective.py:61-95 (Objective.__radd__/__sub__/__rsub__/
## __mul__/__rmul__/__div__), :137-145 (Minimize.__add__), :134-135
## (Minimize.__neg__), :213-221 (Maximize.__add__), :210-211 (Maximize.__neg__).
##
## The four helpers above already implemented CVXPY's semantics exactly --
## including the direction flip, `(is Maximize) == (scalar < 0)` -- but nothing
## dispatched to them, so `Minimize(f) * 2` failed with R's "non-numeric
## argument to binary operator". Registered in .onLoad(), mirroring the
## Expression and Problem handlers (globals.R).
##
## ONE DELIBERATE DEVIATION, for internal consistency: CVXPY accepts `0 + obj`
## (via __radd__) but REJECTS `obj + 0` (Minimize.__add__ demands an Objective).
## That asymmetry is an artifact of Python's __add__/__radd__ split, existing so
## sum() can start from 0; it carries no meaning. R's Ops handler sees both
## operands at once and cannot reproduce it without inventing an arbitrary
## rule, and CVXR's own .problem_Ops_handler already accepts either side. So
## the identity is accepted on BOTH sides here. Everything else -- including
## `1 + obj` raising, and Minimize + Maximize being a DCP error -- matches.
#' @keywords internal
.objective_Ops_handler <- function(e1, e2) {
op <- .Generic
unary <- (nargs() == 1L)
if (unary) {
if (op == "-") return(.negate_objective(e1))
if (op == "+") return(e1)
cli_abort("Unary {.val {op}} is not supported on an objective.")
}
.is_zero <- function(v) is.numeric(v) && length(v) == 1L && !is.na(v) && v == 0
switch(op,
"+" = {
if (.is_zero(e1)) return(e2)
if (.is_zero(e2)) return(e1)
if (!.s7_is(e1, Objective) || !.s7_is(e2, Objective))
cli_abort("An objective can only be added to another objective, or to {.val 0}.")
.add_objectives(e1, e2)
},
"-" = {
if (.is_zero(e1)) return(.negate_objective(e2))
if (.is_zero(e2)) return(e1)
if (!.s7_is(e1, Objective) || !.s7_is(e2, Objective))
cli_abort("An objective can only be subtracted from another objective.")
.sub_objectives(e1, e2)
},
"*" = {
if (.s7_is(e1, Objective) && is.numeric(e2)) .mul_objective(e1, e2)
else if (is.numeric(e1) && .s7_is(e2, Objective)) .mul_objective(e2, e1)
else cli_abort("An objective can only be multiplied by a numeric scalar.")
},
"/" = {
if (!.s7_is(e1, Objective) || !is.numeric(e2))
cli_abort("An objective can only be divided by a numeric scalar.")
.div_objective(e1, e2)
},
cli_abort("Operator {.val {op}} is not supported on an objective.")
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.