R/221_reductions_dqcp2dcp_inverse.R

Defines functions .dqcp_invertible .dqcp_inverse

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/dqcp2dcp/inverse.R
#####

## CVXPY SOURCE: reductions/dqcp2dcp/inverse.py
## Invertibility checks and inverse functions for DQCP atoms

## Compute the inverse of an invertible expression
## Returns a closure function(t) -> expression
## CVXPY SOURCE: inverse.py inverse()
.dqcp_inverse <- function(expr) {
  if (S7_inherits(expr, Ceil)) {
    return(function(t) Floor(t))
  } else if (S7_inherits(expr, Floor)) {
    return(function(t) Ceil(t))
  } else if (S7_inherits(expr, NegExpression)) {
    return(function(t) -t)
  } else if (S7_inherits(expr, Exp)) {
    return(function(t) {
      if (is_nonneg(t)) Log(t) else -Inf
    })
  } else if (S7_inherits(expr, Log)) {
    return(function(t) Exp(t))
  } else if (S7_inherits(expr, Log1p)) {
    return(function(t) Exp(t) - 1)
  } else if (S7_inherits(expr, Logistic)) {
    return(function(t) {
      if (is_nonneg(t)) Log(Exp(t) - 1) else -Inf
    })
  } else if (S7_inherits(expr, Power)) {
    p_val <- expr@p_orig
    return(function(t) {
      if (p_val == 1) return(t)
      if (is_nonneg(t)) power(t, 1 / p_val) else Inf
    })
  } else if (S7_inherits(expr, MulExpression)) {
    if (is_constant(expr@args[[1L]])) {
      const <- expr@args[[1L]]
    } else {
      const <- expr@args[[2L]]
    }
    return(function(t) DivExpression(t, const))
  } else if (S7_inherits(expr, DivExpression)) {
    if (is_constant(expr@args[[1L]])) {
      const <- expr@args[[1L]]
      return(function(t) DivExpression(const, t))
    } else {
      const <- expr@args[[2L]]
      return(function(t) MulExpression(const, t))
    }
  } else if (S7_inherits(expr, AddExpression)) {
    if (is_constant(expr@args[[1L]])) {
      const <- expr@args[[1L]]
    } else {
      const <- expr@args[[2L]]
    }
    return(function(t) t - const)
  } else if (S7_inherits(expr, Abs)) {
    arg <- expr@args[[1L]]
    if (is_nonneg(arg)) {
      return(function(t) t)
    } else if (is_nonpos(arg)) {
      return(function(t) -t)
    } else {
      cli_abort("Sign of argument to {.cls Abs} must be known for DQCP inversion.")
    }
  } else if (S7_inherits(expr, SumEntries) || S7_inherits(expr, Cumsum)) {
    return(function(t) t)
  } else {
    cls <- class(expr)[[1L]]
    cli_abort("Cannot compute inverse of {.cls {cls}}.")
  }
}

## Check if an expression is invertible
## CVXPY SOURCE: inverse.py invertible()
.dqcp_invertible <- function(expr) {
  if (S7_inherits(expr, MulExpression) ||
      S7_inherits(expr, DivExpression) ||
      S7_inherits(expr, AddExpression)) {
    return(length(.non_const_idx(expr)) == 1L)
  } else if (S7_inherits(expr, SumEntries) || S7_inherits(expr, Cumsum)) {
    return(.is_real_fn(expr))
  } else {
    ## Always-invertible atom types
    ## CVXPY SOURCE: inverse.py INVERTIBLE set
    return(
      S7_inherits(expr, Ceil) ||
      S7_inherits(expr, Floor) ||
      S7_inherits(expr, NegExpression) ||
      S7_inherits(expr, Exp) ||
      S7_inherits(expr, Log) ||
      S7_inherits(expr, Log1p) ||
      S7_inherits(expr, Logistic) ||
      S7_inherits(expr, Power) ||
      S7_inherits(expr, Abs)
    )
  }
}

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.