R/188_reductions_complex2real_canonicalizers_matrix_canon.R

Defines functions c2r_matrix_frac_canon c2r_quad_over_lin_canon c2r_quad_canon c2r_lambda_sum_largest_canon c2r_norm_nuc_canon c2r_trace_canon c2r_hermitian_canon .c2r_at_least_2D .c2r_expand_and_reapply .c2r_expand_complex

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

## CVXPY SOURCE: reductions/complex2real/canonicalizers/matrix_canon.py
## Matrix canonicalizers: expand_complex, hermitian_canon, norm_nuc_canon,
## lambda_sum_largest_canon, quad_canon, quad_over_lin_canon,
## matrix_frac_canon, trace_canon

## -- expand_complex ------------------------------------------------
## Expand complex matrix A to B = [[Re(A), -Im(A)], [Im(A), Re(A)]]
## If A is Hermitian, B is symmetric (2x eigenvalues)
.c2r_expand_complex <- function(real_part, imag_part) {
  if (is.null(real_part)) {
    real_part <- Constant(matrix(0, imag_part@shape[1L], imag_part@shape[2L]))
  } else if (is.null(imag_part)) {
    imag_part <- Constant(matrix(0, real_part@shape[1L], real_part@shape[2L]))
  }
  mat <- bmat(list(
    list(real_part, -imag_part),
    list(imag_part, real_part)
  ))
  if (is_symmetric(real_part) && is_skew_symmetric(imag_part)) {
    mat <- symmetric_wrap(mat)
  }
  mat
}

## -- expand_and_reapply --------------------------------------------
.c2r_expand_and_reapply <- function(expr, real_part, imag_part) {
  if (is.null(imag_part)) {
    mat <- real_part
  } else {
    mat <- .c2r_expand_complex(real_part, imag_part)
  }
  expr_copy(expr, list(mat))
}

## -- at_least_2D ---------------------------------------------------
## Upcast 0D and 1D to 2D
.c2r_at_least_2D <- function(expr) {
  if (length(expr@shape) < 2L || (expr@shape[2L] == 1L && expr@shape[1L] == 1L)) {
    reshape_expr(expr, c(expr_size(expr), 1L))
  } else {
    expr
  }
}

## -- hermitian_canon -----------------------------------------------
## For functions that take a Hermitian matrix (lambda_max, sigma_max)
c2r_hermitian_canon <- function(expr, real_args, imag_args, real2imag) {
  expr_canon <- .c2r_expand_and_reapply(expr, real_args[[1L]], imag_args[[1L]])
  list(expr_canon, NULL)
}

## -- trace_canon ---------------------------------------------------
c2r_trace_canon <- function(expr, real_args, imag_args, real2imag) {
  if (is.null(real_args[[1L]])) {
    real_part <- NULL
  } else {
    real_part <- expr_copy(expr, list(real_args[[1L]]))
  }
  if (is.null(imag_args[[1L]]) || is_hermitian(expr)) {
    imag_part <- NULL
  } else {
    imag_part <- expr_copy(expr, list(imag_args[[1L]]))
  }
  list(real_part, imag_part)
}

## -- norm_nuc_canon ------------------------------------------------
## Nuclear norm: eigenvalues doubled, so divide by 2
c2r_norm_nuc_canon <- function(expr, real_args, imag_args, real2imag) {
  result <- c2r_hermitian_canon(expr, real_args, imag_args, real2imag)
  if (!is.null(imag_args[[1L]])) {
    result[[1L]] <- result[[1L]] / 2
  }
  result
}

## -- lambda_sum_largest_canon --------------------------------------
## Each eigenvalue is repeated twice; create new atom with 2*k, divide by 2
c2r_lambda_sum_largest_canon <- function(expr, real_args, imag_args, real2imag) {
  result <- c2r_hermitian_canon(expr, real_args, imag_args, real2imag)
  ## S7 properties are immutable; create new LambdaSumLargest with 2*k
  ## result[[1L]] is already a copy from expand_and_reapply
  ## We need to replace it with a new atom that has doubled k
  if (!is.null(imag_args[[1L]])) {
    expanded_matrix <- .c2r_expand_complex(real_args[[1L]], imag_args[[1L]])
    result[[1L]] <- LambdaSumLargest(expanded_matrix, 2L * expr@k) / 2
  }
  result
}

## -- quad_canon ----------------------------------------------------
## QuadForm: x^H P x -> vstack(Re(x), Im(x))^T [[P_r,-P_i],[P_i,P_r]] vstack(...)
c2r_quad_canon <- function(expr, real_args, imag_args, real2imag) {
  if (is.null(imag_args[[1L]])) {
    vec_arg <- real_args[[1L]]
    mat_arg <- real_args[[2L]]
  } else if (is.null(real_args[[1L]])) {
    vec_arg <- imag_args[[1L]]
    mat_arg <- real_args[[2L]]
  } else {
    vec_arg <- do.call(VStack, list(
      .c2r_at_least_2D(real_args[[1L]]),
      .c2r_at_least_2D(imag_args[[1L]])
    ))
    if (is.null(real_args[[2L]])) {
      real_args[[2L]] <- Constant(matrix(0, imag_args[[2L]]@shape[1L],
                                         imag_args[[2L]]@shape[2L]))
    } else if (is.null(imag_args[[2L]])) {
      imag_args[[2L]] <- Constant(matrix(0, real_args[[2L]]@shape[1L],
                                         real_args[[2L]]@shape[2L]))
    }
    mat_arg <- bmat(list(
      list(real_args[[2L]], -imag_args[[2L]]),
      list(imag_args[[2L]], real_args[[2L]])
    ))
    mat_arg <- psd_wrap(mat_arg)
  }
  list(expr_copy(expr, list(vec_arg, mat_arg)), NULL)
}

## -- quad_over_lin_canon -------------------------------------------
c2r_quad_over_lin_canon <- function(expr, real_args, imag_args, real2imag) {
  if (is.null(imag_args[[1L]])) {
    mat <- real_args[[1L]]
  } else {
    mat <- bmat(list(list(real_args[[1L]], imag_args[[1L]])))
  }
  list(expr_copy(expr, list(mat, real_args[[2L]])), NULL)
}

## -- matrix_frac_canon ---------------------------------------------
c2r_matrix_frac_canon <- function(expr, real_args, imag_args, real2imag) {
  if (is.null(real_args[[1L]])) {
    real_args[[1L]] <- Constant(matrix(0, imag_args[[1L]]@shape[1L],
                                       imag_args[[1L]]@shape[2L]))
  }
  if (is.null(imag_args[[1L]])) {
    imag_args[[1L]] <- Constant(matrix(0, real_args[[1L]]@shape[1L],
                                       real_args[[1L]]@shape[2L]))
  }
  vec_arg <- do.call(VStack, list(
    .c2r_at_least_2D(real_args[[1L]]),
    .c2r_at_least_2D(imag_args[[1L]])
  ))
  if (is.null(real_args[[2L]])) {
    real_args[[2L]] <- Constant(matrix(0, imag_args[[2L]]@shape[1L],
                                       imag_args[[2L]]@shape[2L]))
  } else if (is.null(imag_args[[2L]])) {
    imag_args[[2L]] <- Constant(matrix(0, real_args[[2L]]@shape[1L],
                                       real_args[[2L]]@shape[2L]))
  }
  mat <- bmat(list(
    list(real_args[[2L]], -imag_args[[2L]]),
    list(imag_args[[2L]], real_args[[2L]])
  ))
  list(expr_copy(expr, list(vec_arg, mat)), NULL)
}

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.