R/222_reductions_dqcp2dcp_sets.R

Defines functions .dqcp_superlevel .dqcp_sublevel .dist_ratio_sub .condition_number_sub .gen_lambda_max_sub .length_sub .ratio_sup .ratio_sub .mul_sup .mul_sub

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

## CVXPY SOURCE: reductions/dqcp2dcp/sets.py
## Sublevel and superlevel set registries for DQCP atoms

## Sublevel set: x such that f(x) <= t
## Superlevel set: x such that f(x) >= t
## Returns a list of constraints (some may be lazy closures)

## CVXPY SOURCE: sets.py mul_sub
## CVXPY uses: [y <= t * inv_pos(x)] -- NOT t/x (DivExpression is not DCP)
.mul_sub <- function(expr, t) {
  x <- expr@args[[1L]]
  y <- expr@args[[2L]]
  if (is_nonneg(x) && is_nonpos(y)) {
    list(Inequality(y, t * inv_pos(x)))
  } else if (is_nonpos(x) && is_nonneg(y)) {
    list(Inequality(x, t * inv_pos(y)))
  } else {
    cli_abort("Incorrect signs for multiply sublevel set.")
  }
}

## CVXPY SOURCE: sets.py mul_sup
## CVXPY uses: [x >= t * inv_pos(y)] -- NOT t/y
.mul_sup <- function(expr, t) {
  x <- expr@args[[1L]]
  y <- expr@args[[2L]]
  if (is_nonneg(x) && is_nonneg(y)) {
    list(Inequality(t * inv_pos(y), x))
  } else if (is_nonpos(x) && is_nonpos(y)) {
    list(Inequality(t * inv_pos(-y), -x))
  } else {
    cli_abort("Incorrect signs for multiply superlevel set.")
  }
}

## CVXPY SOURCE: sets.py ratio_sub
## CVXPY uses: [x <= t * y] -- elementwise Multiply, not MulExpression
.ratio_sub <- function(expr, t) {
  x <- expr@args[[1L]]
  y <- expr@args[[2L]]
  if (is_nonneg(y)) {
    list(Inequality(x, t * y))
  } else if (is_nonpos(y)) {
    list(Inequality(t * y, x))
  } else {
    cli_abort("The denominator's sign must be known.")
  }
}

## CVXPY SOURCE: sets.py ratio_sup
## CVXPY uses: [x >= t * y] -- elementwise Multiply, not MulExpression
.ratio_sup <- function(expr, t) {
  x <- expr@args[[1L]]
  y <- expr@args[[2L]]
  if (is_nonneg(y)) {
    list(Inequality(t * y, x))
  } else if (is_nonpos(y)) {
    list(Inequality(x, t * y))
  } else {
    cli_abort("The denominator's sign must be known.")
  }
}

## CVXPY SOURCE: sets.py length_sub
## Sublevel set: {x : length(x) <= t} <=> x[floor(t):] == 0
.length_sub <- function(expr, t) {
  arg <- expr@args[[1L]]
  if (S7_inherits(t, Parameter)) {
    ## Lazy constraint: evaluated at bisection time when t has a value
    sublevel_set <- function() {
      tv <- value(t)
      if (tv < 0) return(FALSE)
      n <- prod(arg@shape)
      if (tv >= n) return(TRUE)
      idx_start <- as.integer(floor(tv)) + 1L  # 1-based, first zero position
      if (idx_start > n) return(TRUE)
      arg[idx_start:n] == 0
    }
    return(list(sublevel_set))
  } else {
    idx_start <- as.integer(floor(value(t))) + 1L
    n <- prod(arg@shape)
    if (idx_start > n) return(list())
    return(list(arg[idx_start:n] == 0))
  }
}

## CVXPY SOURCE: sets.py gen_lambda_max_sub
## Sublevel set: {(A,B) : lambda_max(A,B) <= t} <=> A == A^T, B >> 0, t*B - A >> 0
.gen_lambda_max_sub <- function(expr, t) {
  A <- expr@args[[1L]]
  B <- expr@args[[2L]]
  list(
    Equality(A, t(A)),
    PSD(B),
    PSD(t * B - A)
  )
}

## CVXPY SOURCE: sets.py condition_number_sub
## Sublevel set: {A : cond(A) <= t} uses auxiliary scalar u > 0
## with u*I <= A <= u*t*I (both semidefinite)
.condition_number_sub <- function(expr, t) {
  A <- expr@args[[1L]]
  n <- A@shape[1L]
  u <- Variable(pos = TRUE)

  prom_ut <- cvxr_promote(u * t, c(n, 1L))
  prom_u  <- cvxr_promote(u, c(n, 1L))
  tmp_expr1 <- A - DiagVec(prom_u)
  tmp_expr2 <- DiagVec(prom_ut) - A

  list(
    Equality(upper_tri(A), upper_tri(t(A))),
    PSD(A),
    PSD(tmp_expr1),
    PSD(tmp_expr2)
  )
}

## CVXPY SOURCE: sets.py dist_ratio_sub
## Sublevel set: {x : dist_ratio(x,a,b) <= t}
## Lazy closure -- evaluated at bisection time when t has a value.
.dist_ratio_sub <- function(expr, t) {
  x <- expr@args[[1L]]
  a <- expr@a
  b <- expr@b

  sublevel_set <- function() {
    tv <- as.numeric(value(t))
    if (tv > 1) return(FALSE)
    tsq <- tv^2
    ## (1 - tsq^2)*||x||^2 - 2*(a - tsq*b)^T x + ||a||^2 - tsq*||b||^2 <= 0
    coeff <- as.numeric(2 * (as.numeric(a) - tsq * as.numeric(b)))
    (1 - tsq^2) * sum_squares(x) -
      Constant(matrix(coeff, nrow = 1L)) %*% x +
      sum(as.numeric(a)^2) - tsq * sum(as.numeric(b)^2) <= 0
  }
  list(sublevel_set)
}

## Dispatch sublevel/superlevel via S7_inherits
## CVXPY SOURCE: sets.py sublevel()
.dqcp_sublevel <- function(expr, t) {
  if (S7_inherits(expr, MulExpression)) {
    return(.mul_sub(expr, t))
  } else if (S7_inherits(expr, DivExpression)) {
    return(.ratio_sub(expr, t))
  } else if (S7_inherits(expr, Length)) {
    return(.length_sub(expr, t))
  } else if (S7_inherits(expr, GenLambdaMax)) {
    return(.gen_lambda_max_sub(expr, t))
  } else if (S7_inherits(expr, ConditionNumber)) {
    return(.condition_number_sub(expr, t))
  } else if (S7_inherits(expr, DistRatio)) {
    return(.dist_ratio_sub(expr, t))
  }
  cls <- class(expr)[[1L]]
  cli_abort("The {.cls {cls}} atom is not yet supported in DQCP sublevel sets.")
}

## CVXPY SOURCE: sets.py superlevel()
.dqcp_superlevel <- function(expr, t) {
  if (S7_inherits(expr, MulExpression)) {
    return(.mul_sup(expr, t))
  } else if (S7_inherits(expr, DivExpression)) {
    return(.ratio_sup(expr, t))
  }
  cls <- class(expr)[[1L]]
  cli_abort("The {.cls {cls}} atom is not yet supported in DQCP superlevel sets.")
}

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.