R/163_reductions_dcp2cone_canonicalizers_geo_mean_canon.R

Defines functions geo_mean_approx_canon geo_mean_exact_canon

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

## CVXPY SOURCE: reductions/dcp2cone/canonicalizers/geo_mean_canon.py
## Exact: Uses PowConeND constraints
## Approx: Uses gm_constrs (SOC constraints via rational approximation)
##
## Both work on the aligned view (.gm_aligned_arg, atoms/geo_mean.R): one row
## per reduced entry, one column per output, so one set of constraints covers
## every output.


# -- geo_mean_exact_canon ------------------------------------------
## CVXPY SOURCE: dcp2cone/canonicalizers/geo_mean_canon.py lines 29-51
geo_mean_exact_canon <- function(expr, args, solver_context = NULL) {
  w <- expr@w
  W <- .gm_aligned_arg(expr, args[[1L]])
  shape <- .shape(expr)

  ## Single non-zero weight: geo_mean is just that element (affine)
  if (length(w) == 1L) return(list(.gm_to_shape(W[1L, ], shape), list()))

  ## PowConeND takes one cone per column of W. CVXPY's t is 1-D; CVXR's is
  ## a column (PowConeND's dual recovery assigns z a k x 1 value).
  k <- .shape(W)[2L]
  t <- Variable(c(k, 1L))
  alpha <- matrix(as.numeric(w), nrow = length(w), ncol = k)
  list(.gm_to_shape(t, shape), list(PowConeND(W, t, alpha, axis = 2L)))
}

# -- geo_mean_approx_canon ----------------------------------------
## CVXPY SOURCE: dcp2cone/canonicalizers/geo_mean_canon.py lines 54-93
## Uses gm_constrs (SOC constraints via rational approximation)
geo_mean_approx_canon <- function(expr, args, solver_context = NULL) {
  w <- expr@w
  x <- .gm_aligned_arg(expr, args[[1L]])
  shape <- .shape(expr)

  ## Single non-zero weight: geo_mean is just that element (affine)
  if (length(w) == 1L) return(list(.gm_to_shape(x[1L, ], shape), list()))

  ## gm_constrs is shape-generic: t and every x_list entry are 1 x k (a row
  ## of the aligned view), so all k outputs share one set of constraints.
  ## x[i, ] is row i -- NOT x[i], which would be linear indexing.
  t <- Variable(c(1L, .shape(x)[2L]))
  x_list <- lapply(seq_along(w), function(i) x[i, ])

  constrs <- gm_constrs(t, x_list, w)

  ## CVXPY SOURCE: geo_mean_canon.py:73-89
  .maybe_warn_soc_approx(
    solver_context, target_cone = PowConeND,
    approx_error = expr@approx_error, num_soc = length(constrs),
    msg_head = "geo_mean is being approximated"
  )

  list(.gm_to_shape(t, shape), constrs)
}

method(dcp_canonicalize, GeoMean) <- geo_mean_exact_canon
method(has_dcp_canon, GeoMean) <- function(expr) TRUE
method(dcp_canonicalize, GeoMeanApprox) <- geo_mean_approx_canon
method(has_dcp_canon, GeoMeanApprox) <- function(expr) TRUE

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.