This is a ground-up rewrite of CVXR using R’s S7 object system, designed to be isomorphic with CVXPY 1.8.1 for long-term maintainability. ~4-5x faster than CVXR 1.0-15 on typical problems.
boolean = TRUE or integer = TRUE in
Variable()).Parameter() class with DPP
(Disciplined Parameterized Programming) for efficient re-solves when
only parameter values change.psolve() as the primary solve interface, returning the
optimal value directly.solve() backward-compatibility wrapper returning a
cvxr_result list with $value,
$status, $solver, $getValue(),
and $getDualValue().verbose = TRUE option in psolve() for
structured solve output with timing information.feastol,
reltol, abstol, num_iter) in
psolve() with automatic translation to solver-native names
via solver_default_param(). Solver-native parameters in
... take priority.problem_data(),
solve_via_data(), problem_unpack_results() for
compile-once/solve-many workflows.visualize() for problem introspection: text display
with Smith form annotations, interactive HTML output (D3 tree + KaTeX),
on-demand DCP violation analysis for non-compliant problems, curvature
coloring on constraint nodes, and matrix stuffing visualization (Stages
4-5: Standard Form + Solver Data) via the new solver
parameter.as_cvxr_expr().
Sparse Matrix objects (dgCMatrix, dgeMatrix,
etc.) use S4 dispatch which preempts S7/S3, so direct arithmetic like
sparseA %*% x fails. Wrapping with
as_cvxr_expr(sparseA) %*% x converts to a CVXR Constant
while preserving sparsity. Base R matrix and
numeric work natively without wrapping.+ and -
operators, matching CVXPY’s Expression.broadcast().
Expressions with compatible but different shapes (e.g.,
(1, n) + (m, 1) → (m, n)) now work correctly
in constraints and objectives. Previously only scalar promotion was
supported.MatrixFrac,
TrInv, SigmaMax, NormNuc,
LambdaSumLargest) are now correctly classified, ensuring
solvers like ECOS that don’t support SDP are rejected with a clear error
message instead of a cryptic dimension mismatch. Approximate variants
(PnormApprox, PowerApprox,
GeoMeanApprox) correctly route to SOC; exact variants route
to their native cone types (PowCone3D,
PowConeND).Variable(n) instead of
new("Variable", n).chooseOpsMethod() and S7
@ support).solve() now returns a cvxr_result S3 list,
not an S4 object. Use psolve() for a direct numeric return
value.getValue(x) and getDualValue(con) are
deprecated. Use value(x) and dual_value(con)
after solving instead.problem_status(), problem_solution(), and
get_problem_data() are deprecated. Use
status(), solution(), and
problem_data() instead.axis parameter uses 1-based indexing matching R’s
apply() MARGIN convention: axis = 1 for
row-wise (reduce columns), axis = 2 for column-wise (reduce
rows), axis = NULL for all entries.is(x, "Variable") no longer work.
Use S7_inherits(x, Variable).ptp(x, axis, keepdims) – peak-to-peak (range):
max(x) - min(x).cvxr_mean(x, axis, keepdims) – arithmetic mean along an
axis.cvxr_std(x, axis, keepdims, ddof) – standard
deviation.cvxr_var(x, axis, keepdims, ddof) – variance.vdot(x, y) – vector dot product (inner product).scalar_product(x, y) – alias for
vdot.cvxr_outer(x, y) – outer product of two vectors.inv_prod(x) – reciprocal of product of entries.loggamma(x) – elementwise log of gamma function
(piecewise linear approximation).log_normcdf(x) – elementwise log of standard normal CDF
(quadratic approximation).cummax_expr(x, axis) – cumulative maximum along an
axis.dotsort(X, W) – weighted sorted dot product
(generalization of
sum_largest/sum_smallest).diff_pos(), resolvent() – DGP convenience
functions.status(prob) – returns the solution status (replaces
problem_status()).solution(prob) – returns the raw Solution object
(replaces problem_solution()).problem_data(prob, solver) – returns solver-ready data
(replaces get_problem_data()).tv() is a deprecated alias for
total_variation().norm2(x) is a deprecated alias for
p_norm(x, 2).multiply(x, y) is a deprecated alias for
x * y.installed_solvers() lists available solver
packages.psolve(prob, gp = TRUE). New atoms:
prod_entries(), cumprod(),
one_minus_pos(), eye_minus_inv(),
pf_eigenvalue(), gmatmul().psolve(prob, qcp = TRUE). New atoms:
ceil_expr(), floor_expr(),
condition_number(), gen_lambda_max(),
dist_ratio().Variable(n, complex = TRUE) and Complex2Real
reduction. Atoms: Conj_(), Real_(),
Imag_(), expr_H() for conjugate
transpose.perspective(f, s) atom for perspective functions.FiniteSet(expr, values) constraint for discrete
optimization.Not(), And(),
Or(), Xor(), implies(),
iff().%>>% and %<<% operators for
PSD and NSD constraints.as_cvxr_expr() helper for wrapping R objects as CVXR
constants. Required for Matrix package objects (dgCMatrix,
dgeMatrix, etc.) which use S4 dispatch that preempts S7/S3.
Preserves sparsity (unlike as.matrix()). Base R
matrix/numeric work natively without
wrapping.kron() KRON_L coefficient matrix
construction.CvxAttr2Constr index type and matrix variable
handling.diag offset for super/sub-diagonals
(k != 0).suc - slc
reconstruction).dgCMatrix,
dgeMatrix, ddiMatrix,
sparseVector) cannot be used directly with CVXR operators
due to S4 dispatch preempting S7/S3. Wrap with
as_cvxr_expr() first. Base R
matrix/numeric work natively. This is an R
dispatch limitation requiring upstream changes in S7 and/or Matrix.highs package lacks
setSolution() API).diffcp,
no R equivalent).clarabel requirement and use enhance rather than
import until really necessary (Issue 142).user_limit etc to be
infeasible_inaccurate to match CVXPY for
gurobisolve().upper_tri_to_full to C++Power object (Issue 145).qp2quad_form.Rextract_quadratic_coeffs to use sparse matrix and
sweep in place for better memory use (reported by Marissa Reitsma)Rmosek to be removed from CRAN, so moved to drat
repodgCMatrix via
(as(as(<matrix>, "CsparseMatrix"), "generalMatrix"))inherits()MOSEK and
uncommented associated test.ParameterOSQP and updates to solver cacheDropped delay_load parameter dropped in
reticulate::import_from_path, per changes in
reticulate.
Cleaned up hooks into reticulate for commercial solvers.
LPSOLVE via lpSolveAPIGLPK via RglpkMOSEKGUROBIdrop = FALSE (in function
Index.get_special_slice) as suspected.Added a note that CVXR can probably be compiled from source for earlier versions of R. This is issue #24
Bug fix: issue
#28 Function intf_sign (interface.R) was
unnecessarily using a tolerance parameter, now eliminated.
Updated Solver.solve to adapt to new ECOSolveR. Require version 0.4 of ECOSolveR now.
Updated unpack_results to behave exactly like in
CVXPY. Added documentation and testthat tests. Documented in the Speed.