R/127_constraints_exponential.R

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/constraints/exponential.R
#####

## CVXPY SOURCE: constraints/exponential.py
## ExpCone -- Exponential Cone constraint

#' Create an Exponential Cone Constraint
#'
#' Constrains \eqn{(x, y, z)} to lie in the exponential cone:
#' \deqn{K = \{(x,y,z) \mid y \exp(x/y) \le z,\; y > 0\}}
#'
#' All three arguments must be affine, real, and have the same shape.
#'
#' @param x_expr A CVXR expression.
#' @param y_expr A CVXR expression.
#' @param z_expr A CVXR expression.
#' @param constr_id Optional integer constraint ID.
#' @returns An \code{ExpCone} constraint object.
#' @export
ExpCone <- new_class("ExpCone", parent = Cone, package = "CVXR",
  properties = list(
    .x = new_property(class = Expression),
    .y = new_property(class = Expression),
    .z = new_property(class = Expression)
  ),
  constructor = function(x_expr, y_expr, z_expr, constr_id = NULL) {
    x_expr <- as_expr(x_expr)
    y_expr <- as_expr(y_expr)
    z_expr <- as_expr(z_expr)

    ## CVXPY SOURCE: exponential.py lines 65-67
    args <- list(x_expr, y_expr, z_expr)
    for (val in args) {
      if (!(is_affine(val) && is_real(val))) {
        cli_abort("All arguments must be affine and real.")
      }
    }

    ## CVXPY SOURCE: exponential.py lines 68-72
    xs <- x_expr@shape
    ys <- y_expr@shape
    zs <- z_expr@shape
    if (!identical(xs, ys) || !identical(xs, zs)) {
      cli_abort(
        "All arguments must have the same shapes. Provided shapes: ({xs[1]},{xs[2]}), ({ys[1]},{ys[2]}), ({zs[1]},{zs[2]})."
      )
    }

    if (is.null(constr_id)) constr_id <- next_expr_id()

    ## CVXPY SOURCE: exponential.py lines 134-137 -- shape override
    ## shape = (3,) + self.x.shape -> R 2D: c(3, prod(x_shape))
    cone_shape <- c(3L, as.integer(prod(xs)))

    dvars <- lapply(args, function(a) Variable(a@shape))

    new_object(S7_object(),
      id    = as.integer(constr_id),
      .cache = new.env(parent = emptyenv()),
      args  = args,
      dual_variables = dvars,
      shape = cone_shape,
      .label = "",
      .x = x_expr,
      .y = y_expr,
      .z = z_expr
    )
  }
)

# -- expr_name ----------------------------------------------------
## CVXPY SOURCE: exponential.py lines 75-76

method(expr_name, ExpCone) <- function(x) {
  sprintf("ExpCone(%s, %s, %s)",
    expr_name(x@.x), expr_name(x@.y), expr_name(x@.z))
}

# -- is_dcp -------------------------------------------------------
## CVXPY SOURCE: exponential.py lines 120-126

method(is_dcp, ExpCone) <- function(x) {
  .all_args(x, is_affine)
}

# -- is_dgp -------------------------------------------------------
## CVXPY SOURCE: exponential.py lines 128-129

method(is_dgp, ExpCone) <- function(x) FALSE

# -- num_cones ----------------------------------------------------
## CVXPY SOURCE: exponential.py lines 102-105

method(num_cones, ExpCone) <- function(x) {
  expr_size(x@.x)
}

# -- cone_sizes ---------------------------------------------------
## CVXPY SOURCE: exponential.py lines 110-118

method(cone_sizes, ExpCone) <- function(x) {
  rep(3L, num_cones(x))
}

# -- constr_size --------------------------------------------------
## CVXPY SOURCE: exponential.py lines 97-100

method(constr_size, ExpCone) <- function(x) {
  3L * num_cones(x)
}

# -- residual -----------------------------------------------------
## CVXPY SOURCE: exponential.py lines 82-94
## TODO: The projection should be implemented directly.
## For now, return a simple feasibility check.

method(residual, ExpCone) <- function(x) {
  xv <- value(x@.x)
  yv <- value(x@.y)
  zv <- value(x@.z)
  if (is.null(xv) || is.null(yv) || is.null(zv)) return(NULL)

  ## Feasibility: y*exp(x/y) <= z for y > 0
  ## For y = 0: x <= 0 and z >= 0
  xv <- as.numeric(xv)
  yv <- as.numeric(yv)
  zv <- as.numeric(zv)
  n <- length(xv)
  resid <- numeric(n)
  for (i in seq_len(n)) {
    if (yv[i] > 0) {
      lhs <- yv[i] * exp(xv[i] / yv[i])
      resid[i] <- max(0, lhs - zv[i])
    } else if (yv[i] == 0) {
      resid[i] <- max(0, xv[i]) + max(0, -zv[i])
    } else {
      resid[i] <- abs(yv[i]) + max(0, xv[i]) + max(0, -zv[i])
    }
  }
  if (n == 1L) resid[1L] else resid
}

# -- save_dual_value ----------------------------------------------
## CVXPY SOURCE: exponential.py lines 139-147
## Uses C-order reshape (CR-1)
## CVXPY: np.reshape(value, (-1, 3)) then extracts columns

method(save_dual_value, ExpCone) <- function(x, val) {
  nc <- num_cones(x)
  ## CVXPY: np.reshape(value, (-1, 3)) in C-order
  val_mat <- .reshape_c_order(val, nc, 3L)
  dv0 <- matrix(val_mat[, 1L], nrow = x@.x@shape[1L], ncol = x@.x@shape[2L])
  dv1 <- matrix(val_mat[, 2L], nrow = x@.y@shape[1L], ncol = x@.y@shape[2L])
  dv2 <- matrix(val_mat[, 3L], nrow = x@.z@shape[1L], ncol = x@.z@shape[2L])
  value(x@dual_variables[[1L]]) <- dv0
  value(x@dual_variables[[2L]]) <- dv1
  value(x@dual_variables[[3L]]) <- dv2
  invisible(x)
}

# -- dual_cone ----------------------------------------------------
## CVXPY SOURCE: exponential.py lines 149-162
## dual = ExpCone(-y, -x, e*z)

method(dual_cone, ExpCone) <- function(x, ...) {
  args <- list(...)
  if (length(args) == 0L) {
    ExpCone(-x@dual_variables[[2L]], -x@dual_variables[[1L]],
            exp(1) * x@dual_variables[[3L]])
  } else {
    ExpCone(-args[[2L]], -args[[1L]], exp(1) * args[[3L]])
  }
}

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.