R/233_reductions_dnlp2smooth_canonicalizers_power_canon.R

Defines functions .smooth_power_canon

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

## CVXPY SOURCE: reductions/dnlp2smooth/canonicalizers/power_canon.py
## Canonicalize x^p. Integer p>1 is kept (the diff engine handles polynomials);
## fractional p>0 introduces a nonneg copy; p<0 reduces to 1/(x^{-p}) via div.

.dnlp_power_MIN_INIT <- 1e-3

.smooth_power_canon <- function(expr, args) {
  x <- args[[1L]]
  p <- expr@p_used
  shape <- .shape(expr)
  if (p == 0) {
    return(list(Constant(matrix(1, shape[1L], shape[2L])), list()))
  } else if (p == 1) {
    return(list(x, list()))
  } else if (p > 1 && p == round(p)) {
    ## integer power > 1: smooth polynomial, keep as-is
    return(list(expr_copy(expr, args), list()))
  } else if (p > 0) {
    t <- Variable(shape, nonneg = TRUE)
    v <- value(x)
    if (!is.null(v)) value(t) <- pmax(v, .dnlp_power_MIN_INIT)
    return(list(expr_copy(expr, list(t)), list(t == x)))
  } else {
    ## p < 0, so -p > 0. Canonicalize x^{-p} first, then wrap in 1/(...).
    ## CVXPY does `x ** (-p)`; `p_used` is a gmp::bigq here, and R's power()
    ## rejects a bigq exponent (is.numeric() is FALSE), so coerce to double --
    ## power() re-fractionalizes it internally, matching CVXPY's Fraction path.
    inner_power_expr <- power(x, as.numeric(-p))
    inner_res <- .smooth_power_canon(inner_power_expr, .args(inner_power_expr))
    div_expr <- Constant(matrix(1, shape[1L], shape[2L])) / inner_res[[1L]]
    div_res <- .smooth_div_canon(div_expr, .args(div_expr))
    list(div_res[[1L]], c(inner_res[[2L]], div_res[[2L]]))
  }
}

Try the CVXR package in your browser

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

CVXR documentation built on Aug. 24, 2026, 9:10 a.m.