Nothing
#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/transforms/scalarize.R
#####
## CVXPY SOURCE: transforms/scalarize.py
## Scalarize -- combine several objectives into one for multi-objective problems.
##
## CVXPY exposes these as the submodule `cvxpy.transforms.scalarize`, called as
## `scalarize.weighted_sum(...)`, `scalarize.max(...)`, etc. R has no submodule
## namespacing, so we export a single list object `scalarize` whose members
## mirror the Python functions 1:1 -- `scalarize$weighted_sum(...)`,
## `scalarize$max(...)`, `scalarize$log_sum_exp(...)`,
## `scalarize$targets_and_priorities(...)`. The element `max` deliberately
## shadows base `max` only inside the list, so base R is unaffected.
##
## Objective arithmetic (negate / add / multiply-by-scalar) is provided by the
## helpers in problems/objective.R (.negate_objective, .add_objectives,
## .mul_objective); these mirror CVXPY's Objective.__neg__/__add__/__mul__.
## weighted_sum: sum_i weights[i] * objectives[i].
## CVXPY SOURCE: scalarize.py:21-32
.scalarize_weighted_sum <- function(objectives, weights) {
num_objs <- length(objectives)
scaled <- lapply(seq_len(num_objs), function(i) {
.mul_objective(objectives[[i]], weights[[i]])
})
Reduce(.add_objectives, scaled)
}
## targets_and_priorities: penalize each objective within [target, limit].
## CVXPY SOURCE: scalarize.py:35-138
.scalarize_targets_and_priorities <- function(objectives, priorities, targets,
limits = NULL, off_target = 1e-5) {
if (length(objectives) != length(priorities)) {
cli_abort("Number of objectives and priorities must match.")
}
if (length(objectives) != length(targets)) {
cli_abort("Number of objectives and targets must match.")
}
if (!is.null(limits) && length(objectives) != length(limits)) {
cli_abort("Number of objectives and limits must match.")
}
if (off_target < 0) {
cli_abort("The off_target argument must be nonnegative.")
}
num_objs <- length(objectives)
new_objs <- vector("list", num_objs)
obj_is_min <- logical(num_objs)
for (i in seq_len(num_objs)) {
obj <- objectives[[i]]
tar <- targets[[i]]
lim <- if (!is.null(limits)) limits[[i]] else NULL
## Negative priority flips the objective sense (and its target/limit).
if (priorities[[i]] < 0) {
obj <- .negate_objective(obj)
tar <- -tar
if (!is.null(lim)) lim <- -lim
}
is_min <- .s7_is(obj, Minimize)
sign <- if (is_min) 1 else -1
obj_is_min[i] <- is_min
obj_arg <- obj@args[[1L]]
delta <- sign * (obj_arg - tar)
expr <- sign * (abs(priorities[[i]]) - off_target) * pos(delta)
expr <- expr + off_target * obj_arg
if (!is.null(limits)) {
expr <- expr + sign * indicator(list(sign * obj_arg <= sign * lim))
}
new_objs[[i]] <- expr
}
obj_expr <- Reduce(`+`, new_objs)
## When all objectives agree on direction, respect that direction rather than
## relying solely on curvature (ambiguous for affine expressions, e.g. when
## priority <= off_target). CVXPY SOURCE: scalarize.py:118-138
if (all(obj_is_min)) {
if (is_convex(obj_expr)) return(Minimize(obj_expr))
cli_abort("Scalarized objective is not convex.")
} else if (all(!obj_is_min)) {
if (is_concave(obj_expr)) return(Maximize(obj_expr))
cli_abort("Scalarized objective is not concave.")
} else {
if (is_convex(obj_expr)) return(Minimize(obj_expr))
if (is_concave(obj_expr)) return(Maximize(obj_expr))
cli_abort("Scalarized objective is neither convex nor concave.")
}
}
## max: minimize the largest weighted objective term.
## CVXPY SOURCE: scalarize.py:140-151
.scalarize_max <- function(objectives, weights) {
num_objs <- length(objectives)
terms <- lapply(seq_len(num_objs), function(i) {
.mul_objective(objectives[[i]], weights[[i]])@args[[1L]]
})
Minimize(do.call(Maximum, terms))
}
## log_sum_exp: smooth max interpolating weighted_sum (gamma->0) and max
## (gamma->inf). CVXPY SOURCE: scalarize.py:154-178
.scalarize_log_sum_exp <- function(objectives, weights, gamma = 1.0) {
num_objs <- length(objectives)
terms <- lapply(seq_len(num_objs), function(i) {
.mul_objective(objectives[[i]], weights[[i]])@args[[1L]]
})
stacked <- do.call(vstack, terms)
Minimize(log_sum_exp(gamma * stacked) / gamma)
}
#' Scalarize multiple objectives into a single objective
#'
#' Transforms for combining several \code{Minimize}/\code{Maximize} objectives
#' into one objective for multi-objective optimization. Mirrors CVXPY's
#' \code{cvxpy.transforms.scalarize} submodule; access members with \code{$}:
#'
#' \itemize{
#' \item \code{scalarize$weighted_sum(objectives, weights)} -- weighted sum of
#' objectives.
#' \item \code{scalarize$targets_and_priorities(objectives, priorities,
#' targets, limits = NULL, off_target = 1e-5)} -- penalize each objective
#' within a \code{[target, limit]} range; a negative priority flips the
#' objective sense.
#' \item \code{scalarize$max(objectives, weights)} -- minimize the largest
#' weighted objective term.
#' \item \code{scalarize$log_sum_exp(objectives, weights, gamma = 1.0)} --
#' smooth maximum; \code{gamma -> 0} approaches \code{weighted_sum},
#' \code{gamma -> Inf} approaches \code{max}.
#' }
#'
#' @format A named list of four functions.
#' @examples
#' x <- Variable()
#' objs <- list(Minimize(square(x)), Minimize(square(x - 1)))
#' obj <- scalarize$weighted_sum(objs, c(1, 1))
#' \dontrun{psolve(Problem(obj))}
#' @export
scalarize <- list(
weighted_sum = .scalarize_weighted_sum,
targets_and_priorities = .scalarize_targets_and_priorities,
max = .scalarize_max,
log_sum_exp = .scalarize_log_sum_exp
)
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.