Nothing
#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/complex2real/complex2real.R
#####
## CVXPY SOURCE: reductions/complex2real/complex2real.py
## Complex2Real -- lifts complex numbers to a real representation
##
## This is NOT a Canonicalization subclass. It extends Reduction directly
## and implements its own tree-walking canonicalize_tree() method.
## Each node returns a (real_part, imag_part) pair -- not a single expression.
## -- S7 generic for complex-to-real canonicalization ------------------
## Replaces COMPLEX_CANON_METHODS environment lookup.
## Default: assert no imaginary args, return copy with real args.
##
## INHERITANCE SAFETY: Same invariant as dcp_canonicalize -- every subclass
## of a C2R-registered atom must have its own explicit method.
#' Complex-to-real canonicalization dispatch
#'
#' Each complex-aware atom registers its own method. The default asserts all
#' imag_args are NULL and returns list(expr_copy(expr, real_args), NULL).
#' @noRd
c2r_canonicalize <- new_generic("c2r_canonicalize", "expr",
function(expr, real_args, imag_args, real2imag) {
S7_dispatch()
}
)
method(c2r_canonicalize, S7_object) <- function(expr, real_args, imag_args, real2imag) {
if (!all(vapply(imag_args, is.null, logical(1L)))) {
cls_name <- short_class_name(expr)
cli_abort("Complex canonicalization not implemented for {.cls {cls_name}}.")
}
list(expr_copy(expr, real_args), NULL)
}
#' Predicate: does this expression class have a C2R canonicalizer?
#'
#' Used for leaf caching in .c2r_canonicalize_expr().
#' @noRd
has_c2r_canon <- new_generic("has_c2r_canon", "expr",
function(expr) {
S7_dispatch()
}
)
method(has_c2r_canon, S7_object) <- function(expr) FALSE
## -- C2R method registrations ----------------------------------------
## Separable (affine) atoms
## Bmat is a plain function (not a class) -- no registration needed; it composes HStack/VStack
method(c2r_canonicalize, AddExpression) <- c2r_separable_canon
method(c2r_canonicalize, Cumsum) <- c2r_separable_canon
method(c2r_canonicalize, DiagMat) <- c2r_separable_canon
method(c2r_canonicalize, DiagVec) <- c2r_separable_canon
method(c2r_canonicalize, HStack) <- c2r_separable_canon
method(c2r_canonicalize, Index) <- c2r_separable_canon
method(c2r_canonicalize, Promote) <- c2r_separable_canon
method(c2r_canonicalize, Reshape) <- c2r_separable_canon
method(c2r_canonicalize, SumEntries) <- c2r_separable_canon
method(c2r_canonicalize, Transpose) <- c2r_separable_canon
method(c2r_canonicalize, NegExpression) <- c2r_separable_canon
method(c2r_canonicalize, UpperTri) <- c2r_separable_canon
method(c2r_canonicalize, VStack) <- c2r_separable_canon
method(c2r_canonicalize, Trace) <- c2r_trace_canon
## Binary (multiplication-like) atoms
method(c2r_canonicalize, Convolve) <- c2r_binary_canon
method(c2r_canonicalize, DivExpression) <- c2r_binary_canon
method(c2r_canonicalize, Kron) <- c2r_binary_canon
method(c2r_canonicalize, MulExpression) <- c2r_binary_canon
method(c2r_canonicalize, Multiply) <- c2r_binary_canon
## Complex-specific atoms
method(c2r_canonicalize, Conj_) <- c2r_conj_canon
method(c2r_canonicalize, Imag_) <- c2r_imag_canon
method(c2r_canonicalize, Real_) <- c2r_real_canon
method(c2r_canonicalize, hermitian_wrap) <- c2r_hermitian_wrap_canon
## Leaves
method(c2r_canonicalize, Variable) <- c2r_variable_canon
method(c2r_canonicalize, Constant) <- c2r_constant_canon
method(c2r_canonicalize, Parameter) <- c2r_param_canon
## Constraints
method(c2r_canonicalize, Inequality) <- c2r_inequality_canon
method(c2r_canonicalize, PSD) <- c2r_psd_canon
method(c2r_canonicalize, SOC) <- c2r_soc_canon
method(c2r_canonicalize, Equality) <- c2r_equality_canon
method(c2r_canonicalize, Zero) <- c2r_zero_canon
## Abs and norms
method(c2r_canonicalize, Abs) <- c2r_abs_canon
method(c2r_canonicalize, Norm1) <- c2r_pnorm_canon
method(c2r_canonicalize, NormInf) <- c2r_pnorm_canon
method(c2r_canonicalize, Pnorm) <- c2r_pnorm_canon
method(c2r_canonicalize, PnormApprox) <- c2r_pnorm_canon
## Matrix atoms
method(c2r_canonicalize, LambdaMax) <- c2r_hermitian_canon
method(c2r_canonicalize, LogDet) <- c2r_norm_nuc_canon
method(c2r_canonicalize, NormNuc) <- c2r_norm_nuc_canon
method(c2r_canonicalize, SigmaMax) <- c2r_hermitian_canon
method(c2r_canonicalize, QuadForm) <- c2r_quad_canon
method(c2r_canonicalize, QuadOverLin) <- c2r_quad_over_lin_canon
method(c2r_canonicalize, MatrixFrac) <- c2r_matrix_frac_canon
method(c2r_canonicalize, LambdaSumLargest) <- c2r_lambda_sum_largest_canon
## has_c2r_canon registrations for leaf caching
method(has_c2r_canon, AddExpression) <- function(expr) TRUE
method(has_c2r_canon, Cumsum) <- function(expr) TRUE
method(has_c2r_canon, DiagMat) <- function(expr) TRUE
method(has_c2r_canon, DiagVec) <- function(expr) TRUE
method(has_c2r_canon, HStack) <- function(expr) TRUE
method(has_c2r_canon, Index) <- function(expr) TRUE
method(has_c2r_canon, Promote) <- function(expr) TRUE
method(has_c2r_canon, Reshape) <- function(expr) TRUE
method(has_c2r_canon, SumEntries) <- function(expr) TRUE
method(has_c2r_canon, Transpose) <- function(expr) TRUE
method(has_c2r_canon, NegExpression) <- function(expr) TRUE
method(has_c2r_canon, UpperTri) <- function(expr) TRUE
method(has_c2r_canon, VStack) <- function(expr) TRUE
method(has_c2r_canon, Trace) <- function(expr) TRUE
method(has_c2r_canon, Convolve) <- function(expr) TRUE
method(has_c2r_canon, DivExpression) <- function(expr) TRUE
method(has_c2r_canon, Kron) <- function(expr) TRUE
method(has_c2r_canon, MulExpression) <- function(expr) TRUE
method(has_c2r_canon, Multiply) <- function(expr) TRUE
method(has_c2r_canon, Conj_) <- function(expr) TRUE
method(has_c2r_canon, Imag_) <- function(expr) TRUE
method(has_c2r_canon, Real_) <- function(expr) TRUE
method(has_c2r_canon, hermitian_wrap) <- function(expr) TRUE
method(has_c2r_canon, Variable) <- function(expr) TRUE
method(has_c2r_canon, Constant) <- function(expr) TRUE
method(has_c2r_canon, Parameter) <- function(expr) TRUE
method(has_c2r_canon, Inequality) <- function(expr) TRUE
method(has_c2r_canon, PSD) <- function(expr) TRUE
method(has_c2r_canon, SOC) <- function(expr) TRUE
method(has_c2r_canon, Equality) <- function(expr) TRUE
method(has_c2r_canon, Zero) <- function(expr) TRUE
method(has_c2r_canon, Abs) <- function(expr) TRUE
method(has_c2r_canon, Norm1) <- function(expr) TRUE
method(has_c2r_canon, NormInf) <- function(expr) TRUE
method(has_c2r_canon, Pnorm) <- function(expr) TRUE
method(has_c2r_canon, PnormApprox) <- function(expr) TRUE
method(has_c2r_canon, LambdaMax) <- function(expr) TRUE
method(has_c2r_canon, LogDet) <- function(expr) TRUE
method(has_c2r_canon, NormNuc) <- function(expr) TRUE
method(has_c2r_canon, SigmaMax) <- function(expr) TRUE
method(has_c2r_canon, QuadForm) <- function(expr) TRUE
method(has_c2r_canon, QuadOverLin) <- function(expr) TRUE
method(has_c2r_canon, MatrixFrac) <- function(expr) TRUE
method(has_c2r_canon, LambdaSumLargest) <- function(expr) TRUE
# -- complex2real_accepts -------------------------------------------
## CVXPY SOURCE: complex2real.py lines 42-44
complex2real_accepts <- function(problem) {
leaves <- c(variables(problem), constants(problem))
any(vapply(leaves, is_complex, logical(1L)))
}
# -- Complex2Real class ---------------------------------------------
## CVXPY SOURCE: complex2real.py lines 47-309
Complex2Real <- new_class("Complex2Real", parent = Reduction, package = "CVXR",
constructor = function() {
new_object(S7_object(),
.cache = new.env(parent = emptyenv())
)
}
)
## -- accepts -----------------------------------------------------
method(reduction_accepts, Complex2Real) <- function(x, problem, ...) {
complex2real_accepts(problem)
}
## -- apply -------------------------------------------------------
## CVXPY SOURCE: complex2real.py lines 162-198
method(reduction_apply, Complex2Real) <- function(x, problem, ...) {
## Build real2imag mapping for all complex variables and constraints
real2imag <- new.env(hash = TRUE, parent = emptyenv())
for (v in variables(problem)) {
if (is_complex(v)) {
assign(as.character(v@id), next_expr_id(), envir = real2imag)
}
}
for (con in problem@constraints) {
if (is_complex(con)) {
assign(as.character(con@id), next_expr_id(), envir = real2imag)
}
}
## Build inverse_data as a plain list
inverse_data <- list(
real2imag = real2imag,
id2var = new.env(hash = TRUE, parent = emptyenv()),
id2cons = new.env(hash = TRUE, parent = emptyenv())
)
## Populate id2var and id2cons
for (v in variables(problem)) {
assign(as.character(v@id), v, envir = inverse_data$id2var)
}
for (con in problem@constraints) {
assign(as.character(con@id), con, envir = inverse_data$id2cons)
}
leaf_map <- new.env(hash = TRUE, parent = emptyenv())
## Canonicalize objective
obj_result <- .c2r_canonicalize_tree(problem@objective, real2imag, leaf_map)
real_obj <- obj_result[[1L]]
## imag_obj must be NULL for a real-valued objective
## (CVXPY asserts this)
## Canonicalize constraints -- collect chunks, flatten once
n_cons <- length(problem@constraints)
constr_chunks <- vector("list", 2L * n_cons)
for (i in seq_len(n_cons)) {
con_result <- .c2r_canonicalize_tree(problem@constraints[[i]], real2imag, leaf_map)
real_constrs <- con_result[[1L]]
imag_constrs <- con_result[[2L]]
## Normalize to list (canonicalizer may return single constraint or list)
if (S7_inherits(real_constrs, Constraint)) {
constr_chunks[[2L * i - 1L]] <- list(real_constrs)
} else if (is.list(real_constrs)) {
constr_chunks[[2L * i - 1L]] <- real_constrs
}
if (S7_inherits(imag_constrs, Constraint)) {
constr_chunks[[2L * i]] <- list(imag_constrs)
} else if (is.list(imag_constrs)) {
constr_chunks[[2L * i]] <- imag_constrs
}
}
constrs <- unlist(constr_chunks, recursive = FALSE)
if (is.null(constrs)) constrs <- list()
new_problem <- Problem(real_obj, constrs)
list(new_problem, inverse_data)
}
## -- invert ------------------------------------------------------
## CVXPY SOURCE: complex2real.py lines 200-276
method(reduction_invert, Complex2Real) <- function(x, solution, inverse_data, ...) {
pvars <- list()
dvars <- list()
real2imag <- inverse_data$real2imag
id2var <- inverse_data$id2var
id2cons <- inverse_data$id2cons
if (solution@status %in% SOLUTION_PRESENT) {
## -- Primal variables --
for (vid in ls(id2var)) {
var <- get(vid, envir = id2var)
if (is_real(var)) {
pvars[[vid]] <- solution@primal_vars[[vid]]
} else if (is_imag(var)) {
imag_id <- as.character(get(vid, envir = real2imag))
pvars[[vid]] <- 1i * solution@primal_vars[[imag_id]]
} else if (is_complex(var) && is_hermitian(var)) {
pvars[[vid]] <- solution@primal_vars[[vid]]
imag_id <- as.character(get(vid, envir = real2imag))
if (!is.null(solution@primal_vars[[imag_id]])) {
imag_val <- solution@primal_vars[[imag_id]]
## Reconstruct skew-symmetric matrix from strict upper triangle
imag_val <- value(vec_to_upper_tri(Constant(imag_val), strict = TRUE))
imag_val <- imag_val - t(imag_val)
pvars[[vid]] <- pvars[[vid]] + 1i * imag_val
}
} else if (is_complex(var)) {
pvars[[vid]] <- solution@primal_vars[[vid]]
imag_id <- as.character(get(vid, envir = real2imag))
if (!is.null(solution@primal_vars[[imag_id]])) {
pvars[[vid]] <- pvars[[vid]] + 1i * solution@primal_vars[[imag_id]]
}
}
}
## -- Dual variables --
if (length(solution@dual_vars) > 0L) {
for (cid in ls(id2cons)) {
con <- get(cid, envir = id2cons)
if (is_real(con)) {
dvars[[cid]] <- solution@dual_vars[[cid]]
} else if (is_imag(con)) {
imag_id <- as.character(get(cid, envir = real2imag))
dvars[[cid]] <- 1i * solution@dual_vars[[imag_id]]
} else if (S7_inherits(con, Equality) || S7_inherits(con, Zero)) {
imag_id <- as.character(get(cid, envir = real2imag))
if (!is.null(solution@dual_vars[[imag_id]])) {
dvars[[cid]] <- solution@dual_vars[[cid]] +
1i * solution@dual_vars[[imag_id]]
} else {
dvars[[cid]] <- solution@dual_vars[[cid]]
}
} else if (S7_inherits(con, PSD)) {
n <- con@args[[1L]]@shape[1L]
dual <- solution@dual_vars[[cid]]
if (is.null(dual)) {
dvars[[cid]] <- NULL
} else {
## Dual may be vector or matrix; ensure it's a (2n, 2n) matrix
nn <- 2L * n
if (is.null(dim(dual))) dual <- matrix(dual, nn, nn)
dvars[[cid]] <- dual[1L:n, 1L:n] + 1i * dual[(n + 1L):nn, 1L:n]
}
} else if (S7_inherits(con, SOC)) {
## Skip -- unimplemented in CVXPY too
} else {
cli_abort("Unknown constraint type {.val {short_class_name(con)}} in Complex2Real invert.")
}
}
}
}
Solution(status = solution@status,
opt_val = solution@opt_val,
primal_vars = pvars,
dual_vars = dvars,
attr = solution@attr)
}
# -- canonicalize_tree ----------------------------------------------
## CVXPY SOURCE: complex2real.py lines 278-292
## Recursive bottom-up walk: each node returns (real_part, imag_part)
.c2r_canonicalize_tree <- function(expr, real2imag, leaf_map) {
n_args <- length(expr@args)
real_args <- vector("list", n_args)
imag_args <- vector("list", n_args)
for (i in seq_len(n_args)) {
result <- .c2r_canonicalize_tree(expr@args[[i]], real2imag, leaf_map)
## Use single-bracket assignment: [[<- with NULL deletes the element!
real_args[i] <- list(result[[1L]])
imag_args[i] <- list(result[[2L]])
}
.c2r_canonicalize_expr(expr, real_args, imag_args, real2imag, leaf_map)
}
# -- canonicalize_expr ----------------------------------------------
## CVXPY SOURCE: complex2real.py lines 294-309
## Dispatch to canonicalizer; fallback: assert no imag args, copy with real args
.c2r_canonicalize_expr <- function(expr, real_args, imag_args, real2imag, leaf_map) {
## Cache leaves -- only canonicalize once
if (has_c2r_canon(expr) && length(expr@args) == 0L) {
key <- as.character(expr@id)
if (exists(key, envir = leaf_map, inherits = FALSE)) {
return(get(key, envir = leaf_map, inherits = FALSE))
}
result <- c2r_canonicalize(expr, real_args, imag_args, real2imag)
assign(key, result, envir = leaf_map)
return(result)
}
## S7 dispatch -- default method asserts no imag args and returns copy
c2r_canonicalize(expr, real_args, imag_args, real2imag)
}
## DEFERRED: Derivative chain-rule overrides (complex2real.py lines 94-131)
## Complex2Real splits complex parameters into real/imaginary parts, so the
## chain rule for derivatives requires:
##
## param_backward(x, param, dparams) -- recombine real+imag gradients
## param_forward(x, param, delta) -- split delta into real+imag parts
##
## Deferred: derivative API depends on diffcp. See notes/derivative_api_deferred.md.
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.