Nothing
#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/solvers/solver.R
#####
## CVXPY SOURCE: reductions/solvers/solver.py
## Solver -- abstract base class for solver reductions
# -- Solver constants ----------------------------------------------
## CVXPY SOURCE: solver.py lines 28-43
SOLVER_VAR_ID <- "var_id"
SOLVER_DUAL_VAR_ID <- "dual_var_id"
SOLVER_EQ_CONSTR <- "eq_constr"
SOLVER_NEQ_CONSTR <- "other_constr"
# -- expand_cones --------------------------------------------------
## CVXPY SOURCE: solver.py lines 26-68
##
## Given the cones a problem needs and the cones a solver natively supports,
## replace each unsupported-but-convertible cone with what it converts to, and
## report which conversions the chain must therefore run.
##
## `cones` and `supported` are lists of S7 class objects (CVXR stores
## `@SUPPORTED_CONSTRAINTS` that way); CVXPY uses sets of classes, so the set
## operations are spelled out with `.cone_has`.
##
## PARTIAL: CVXR has no APPROX_CONE_CONVERSIONS table -- the SOC approximations
## are chosen inside the dcp2cone canonicalizers (power/geo_mean/pnorm, driven
## by `solver_context`), not by a cone2cone reduction. So `approx_targets` is
## always empty here, and the approximate half of CVXPY's function has no
## counterpart to port yet. See reductions/cone2cone/approx.R.
.cone_has <- function(cone_list, cone) {
any(vapply(cone_list, identical, logical(1L), cone))
}
expand_cones <- function(cones, supported) {
## Which unsupported cones can transitively reach a supported cone via the
## EXACT_CONE_CONVERSIONS DAG? (solver.py:42-51)
reachable <- list()
repeat {
changed <- FALSE
for (entry in EXACT_CONE_CONVERSIONS) {
if (.cone_has(reachable, entry$source)) next
hits <- any(vapply(entry$targets, function(t) {
.cone_has(supported, t) || .cone_has(reachable, t)
}, logical(1L)))
if (hits) {
reachable[[length(reachable) + 1L]] <- entry$source
changed <- TRUE
}
}
if (!changed) break
}
## Expand, following the DAG until nothing new is convertible.
## (solver.py:53-62)
exact_targets <- list()
repeat {
new_targets <- Filter(function(c) {
.cone_has(reachable, c) && !.cone_has(supported, c)
}, cones)
if (length(new_targets) == 0L) break
for (co in new_targets) {
exact_targets[[length(exact_targets) + 1L]] <- co
cones <- Filter(function(c) !identical(c, co), cones)
entry <- Filter(function(e) identical(e$source, co),
EXACT_CONE_CONVERSIONS)[[1L]]
for (t in entry$targets) {
if (!.cone_has(cones, t)) cones[[length(cones) + 1L]] <- t
}
}
}
list(cones = cones, exact_targets = exact_targets,
approx_targets = list())
}
# -- Solver base class --------------------------------------------
## CVXPY SOURCE: solver.py lines 24-90
## PSD constraint format (CVXPY SOURCE: solver.py lines 85-90). Overridden by
## solvers that support PSD constraints in svec form. PSD_TRIANGLE_KIND is the
## triangle the solver expects (`TriangleKind$LOWER` / `$UPPER`); NA means no
## PSD support via this mechanism (CVXPY's `None`), which includes solvers such
## as CVXOPT that take full PSD matrices. PSD_SQRT2_SCALING says whether the
## off-diagonal entries are scaled by sqrt(2).
##
## Constraint 17 ripple: `.fast_new` does not evaluate property defaults, so
## EVERY solver constructor passes both explicitly -- an unset property reads
## back as NULL, not as the class default.
Solver <- new_class("Solver", parent = Reduction, package = "CVXR",
properties = list(
MIP_CAPABLE = new_property(class_logical, default = FALSE),
BOUNDED_VARIABLES = new_property(class_logical, default = FALSE),
PSD_TRIANGLE_KIND = new_property(class_character, default = NA_character_),
PSD_SQRT2_SCALING = new_property(class_logical, default = NA)
),
constructor = function(MIP_CAPABLE = FALSE, BOUNDED_VARIABLES = FALSE,
PSD_TRIANGLE_KIND = NA_character_,
PSD_SQRT2_SCALING = NA) {
if (FALSE) new_object(S7_object()) ## S7 static-check guard
.fast_new(Solver, S7_object(),
.cache = new.env(parent = emptyenv()),
MIP_CAPABLE = MIP_CAPABLE,
BOUNDED_VARIABLES = BOUNDED_VARIABLES,
PSD_TRIANGLE_KIND = PSD_TRIANGLE_KIND,
PSD_SQRT2_SCALING = PSD_SQRT2_SCALING
)
}
)
## name: subclasses must override
method(solver_name, Solver) <- function(x) {
cli_abort("Class {.cls {class(x)[[1L]]}} must implement {.fn solver_name}.")
}
## import_solver / is_installed (solver.py:108-127): DELIBERATELY NOT PORTED.
##
## CVXPY declares `import_solver()` abstract and has each interface implement it as a
## bare `import <pkg>`; `is_installed()` wraps that in try/except. In Python the probe
## IS the mechanism -- there is no registry to consult, so an exception-driven import is
## the only idiom available. R has `requireNamespace()`, which RETURNS a logical, so
## wrapping it in abort-and-catch to recover that same logical would be a Python idiom
## transplanted into a language that does not need it.
##
## CVXR answers "is this solver installed" through a name->package table instead:
##
## .SOLVER_PACKAGES name -> package solving_chain.R:53
## .solver_package_usable memoised requireNamespace solving_chain.R:84
## .solver_package_available the above, minus exclude_solvers()
## .require_solver_package abort form, called by every solve_via_data
## installed_solvers() the exported user-facing answer exports.R:119
##
## Better, not merely different: (a) it resolves each package ONCE per session, where a
## per-class hook called during chain construction would re-probe -- CVXPY itself
## resolves once per process (`INSTALLED_SOLVERS = installed_solvers()`, defines.py:129),
## so the table is closer to upstream's behavior, not further from it; (b) it keeps the
## Rmosek-stub rule (usable only at version >= 10; CRAN's Rmosek is an ancient stub, a
## failure mode Python has no equivalent of) in ONE place that a per-class
## `requireNamespace` would drop or bury.
##
## Until 1.9.1.9044 this file defined `solver_import()` (aborting unconditionally) and
## `solver_is_installed()` (tryCatch around it). No subclass ever implemented the former,
## so the latter answered FALSE for every solver while installed_solvers() listed fifteen.
## Both had ZERO callers and neither was exported. Deleted rather than implemented --
## dead code mimicking an upstream API is worse than no code, because it misleads its
## first caller. Audit finding #4; verdict `deliberate` in
## notes/audit/completeness_known.tsv. Do not re-add.
##
## One caveat recorded separately: MOSEK.import_solver is the only upstream override that
## does more than import -- it appends ExpCone/PowCone3D to SUPPORTED_CONSTRAINTS behind
## a `hasattr(mosek.conetype, 'pexp')` guard. CVXR declares those cones unconditionally
## (mosek_conif.R), which is correct given the Rmosek >= 10 floor. See ledger ยง4a.
## solve_via_data: subclasses must override
method(solve_via_data, Solver) <- function(x, data, warm_start = FALSE, verbose = FALSE,
solver_opts = list(), ...) {
cli_abort("Class {.cls {class(x)[[1L]]}} must implement {.fn solve_via_data}.")
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.