R/195_reductions_complex2real_canonicalizers_variable_canon.R

Defines functions c2r_variable_canon .split_complex_attributes

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/complex2real/canonicalizers/variable_canon.R
#####

## CVXPY SOURCE: reductions/complex2real/canonicalizers/variable_canon.py
## Canonicalize complex variables -> real/imag variable pairs

## CVXPY v1.9.3 fix: #3342 -- attributes that are safe to forward to both the
## full-size real and imaginary split Variables (variable_canon.py:23-26).
## 1.9.3 plan decision D4: in CVXPY this module-level variable_canon is not
## the solve path (Complex2RealCanonMethods._variable_canon is), so complex +
## diag/sparsity stays unenforced upstream; c2r_variable_canon IS CVXR's
## solve path, so CVXR enforces it. Deliberate divergence.
FULL_SIZE_SPLIT_ATTRS <- c("diag", "sparsity")

## CVXPY SOURCE: variable_canon.py:28-53 (_split_complex_attributes).
.split_complex_attributes <- function(attributes) {
  real_attr <- list()
  for (nm in FULL_SIZE_SPLIT_ATTRS) {
    if (.attr_set(attributes[[nm]])) real_attr[[nm]] <- attributes[[nm]]
  }
  imag_attr <- real_attr

  if (isTRUE(attributes$PSD)) real_attr$PSD <- TRUE
  if (isTRUE(attributes$NSD)) real_attr$NSD <- TRUE

  if (isTRUE(attributes$hermitian) &&
      !(isTRUE(attributes$PSD) || isTRUE(attributes$NSD))) {
    real_attr$symmetric <- TRUE
  }
  list(real_attr, imag_attr)
}

c2r_variable_canon <- function(expr, real_args, imag_args, real2imag) {
  if (is_real(expr)) {
    ## Purely real
    return(list(expr, NULL))
  } else if (is_imag(expr)) {
    ## Purely imaginary
    imag_attr <- .split_complex_attributes(.attributes(expr))[[2L]]
    imag_var <- do.call(Variable, c(
      list(.shape(expr), var_id = real2imag[[as.character(.id(expr))]]),
      imag_attr))
    return(list(NULL, imag_var))
  } else if (is_complex(expr) && is_hermitian(expr)) {
    ## Hermitian variable: real part symmetric, imag part skew-symmetric
    n <- .shape(expr)[1L]
    real_attr <- .split_complex_attributes(.attributes(expr))[[1L]]
    real_var <- do.call(Variable, c(list(c(n, n), var_id = .id(expr)), real_attr))
    if (n > 1L) {
      ## The imaginary part is a compact vector of strict upper-triangular
      ## entries, so matrix-shaped imag attributes are not forwarded here.
      imag_var <- Variable(c((n * (n - 1L)) %/% 2L, 1L),
                           var_id = real2imag[[as.character(.id(expr))]])
      imag_upper_tri <- vec_to_upper_tri(imag_var, strict = TRUE)
      ## upper_tri - upper_tri^T to make skew-symmetric
      imag_mat <- skew_symmetric_wrap(imag_upper_tri - t(imag_upper_tri))
    } else {
      imag_mat <- Constant(matrix(0, 1L, 1L))
    }
    return(list(real_var, imag_mat))
  } else {
    ## General complex
    split <- .split_complex_attributes(.attributes(expr))
    real_var <- do.call(Variable, c(list(.shape(expr), var_id = .id(expr)), split[[1L]]))
    imag_var <- do.call(Variable, c(
      list(.shape(expr), var_id = real2imag[[as.character(.id(expr))]]),
      split[[2L]]))
    return(list(real_var, imag_var))
  }
}

Try the CVXR package in your browser

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

CVXR documentation built on Oct. 19, 2026, 5:07 p.m.