R/165_reductions_dcp2cone_canonicalizers_power_canon.R

Defines functions power_approx_canon power_exact_canon

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

## CVXPY SOURCE: reductions/dcp2cone/canonicalizers/power_canon.py
## Uses PowCone3D via powcone_constrs utility (exact)
## Uses gm_constrs (SOC constraints via rational approximation) (approx)


# -- power_exact_canon ----------------------------------------------
power_exact_canon <- function(expr, args, solver_context = NULL) {
  x <- args[[1L]]
  p <- expr@p_used

  if (is.null(p)) {
    cli_abort("Cannot canonicalize Power without known exponent value.")
  }

  if (p == 1) return(list(x, list()))

  shape <- expr@shape
  ones <- Constant(matrix(1, nrow = shape[1L], ncol = shape[2L]))
  if (p == 0) return(list(ones, list()))

  t <- Variable(shape = shape)

  if (p == 2) {
    ## Special case: x^2 -> SOC-based formulation (broader solver support).
    ## x_i^2 <= t_i <=> SOC(t_i + 1, [2*x_i, t_i - 1]) for each element i.
    ## Uses axis=0 SOC for vectorized handling of all elements at once.
    n <- prod(shape)
    x_flat <- .cvxr_vec(x)      ## (n, 1)
    t_flat <- .cvxr_vec(t)      ## (n, 1)
    ones_flat <- Constant(matrix(1, n, 1L))
    x_row <- reshape_expr(2 * x_flat, c(1L, n))
    t_row <- reshape_expr(t_flat - ones_flat, c(1L, n))
    X_body <- VStack(x_row, t_row)  ## (2, n)
    constrs <- list(SOC(t = t_flat + ones_flat, X = X_body, axis = 2L))
    return(list(t, constrs))
  } else if (p > 0 && p < 1) {
    ## 0 < p < 1: t <= x^p <=> PowCone3D(x, 1, t, p)
    alpha <- as.numeric(p)
    return(list(t, powcone_constrs(t, list(x, ones), alpha)))
  } else if (p > 1) {
    ## p > 1: t >= x^p <=> PowCone3D(t, 1, x, 1/p) reversed
    alpha <- as.numeric(1 / p)
    constrs <- powcone_constrs(x, list(t, ones), alpha)
    if (p %% 2 != 0) {
      constrs <- c(constrs, list(x >= 0))
    }
    return(list(t, constrs))
  } else if (p < 0) {
    ## p < 0: t >= x^p <=> PowCone3D(1, x, t, p/(p-1))
    alpha <- as.numeric(p / (p - 1))
    return(list(t, powcone_constrs(ones, list(x, t), alpha)))
  } else {
    cli_abort("Unsupported power value: {p}.")
  }
}

# -- power_approx_canon ---------------------------------------------
## CVXPY SOURCE: dcp2cone/canonicalizers/power_canon.py lines 60-103
## Uses gm_constrs (SOC constraints via rational approximation)
power_approx_canon <- function(expr, args, solver_context = NULL) {
  x <- args[[1L]]
  p <- expr@p_used
  w <- expr@w

  if (is.null(p)) {
    cli_abort("Cannot canonicalize PowerApprox without known exponent value.")
  }

  if (p == 1) return(list(x, list()))

  shape <- expr@shape
  ones <- Constant(matrix(1, nrow = shape[1L], ncol = shape[2L]))
  if (p == 0) return(list(ones, list()))

  t <- Variable(shape = shape)
  if (p > 0 && p < 1) {
    constrs <- gm_constrs(t, list(x, ones), w)
  } else if (p > 1) {
    constrs <- gm_constrs(x, list(t, ones), w)
  } else if (p < 0) {
    constrs <- gm_constrs(ones, list(x, t), w)
  } else {
    cli_abort("Unsupported power value: {p}.")
  }

  list(t, constrs)
}

method(dcp_canonicalize, Power) <- power_exact_canon
method(has_dcp_canon, Power) <- function(expr) TRUE
method(dcp_canonicalize, PowerApprox) <- power_approx_canon
method(has_dcp_canon, PowerApprox) <- 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 March 6, 2026, 9:10 a.m.