
What's New in CVXR
Anqi Fu, Balasubramanian Narasimhan, and Stephen Boyd
2026-06-09
Source:vignettes/whats_new.Rmd
whats_new.RmdThis vignette highlights notable user-facing changes in each release
of the S7 rewrite of CVXR, newest first. For the complete,
fine-grained list see the package NEWS file
(news(package = "CVXR")). For the introductory tutorial,
see vignette("cvxr_intro"); for worked examples, visit the
CVXR website.
- CVXR 1.9.1 — disciplined nonlinear programming, derivatives, bounds propagation, new atoms
- CVXR 1.8.x — the ground-up S7 rewrite
CVXR 1.9.1
CVXR 1.9.1 is the first CRAN release since 1.8.2 and is
a large one: it folds in the internal 1.8.2-1 and 1.9.0 development
cycles. Its headline additions are disciplined nonlinear programming, a
derivative / sensitivity-analysis API, and interval-bounds propagation
with native solver-bound support.
Disciplined Nonlinear Programming (DNLP)
CVXR 1.9.1 extends modeling beyond convex optimization
to smooth nonlinear programs, which need not be convex.
You build the problem from differentiable atoms, check it with
is_dnlp(), and solve it with
psolve(prob, nlp = TRUE). Every DCP problem is also a DNLP,
and the disciplined nonlinear grammar additionally allows smooth atoms
in forms DCP forbids (for example, a product of two variable-dependent
expressions).
x <- Variable(2)
prob <- Problem(Minimize(sum_squares(x - c(1, 2))))
is_dnlp(prob) # TRUE
psolve(prob, nlp = TRUE) # solved through the NLP path-
New smooth atoms usable anywhere in a DNLP:
sin(),cos(),tan(),sinh(),tanh(),asinh(),atanh(),normcdf(), andprod(). -
Nonconvex problems may have several local optima.
best_of = nsolves fromnrandom initial points (drawn from variable bounds orsample_bounds()) and keeps the best. - The NLP path is powered by automatic derivatives from the optional
sparsediffpackage and a nonlinear solver. Two are supported, both inEnhances(so guard their use withrequireNamespace()): UNO (theUnopackage — headed for CRAN, self-contained, and the practical default for R users) and IPOPT (theipoptpackage — not on CRAN owing to licensing, so rarely installed). Withnlp = TRUE, IPOPT is preferred when present (matching CVXPY), otherwise UNO is used. TheUNOpath also recovers constraint duals viadual_value(); theIPOPTpath returns none, matching CVXPY.
See the DNLP Tutorial for worked examples.
Derivatives and sensitivity analysis
CVXR 1.9.1 adds the ability to differentiate the
solution map of a disciplined problem — to see how the optimal
solution responds to small changes in the parameters (sensitivity
analysis) and to compute gradients of scalar functions of the solution.
Request derivatives at solve time with
requires_grad = TRUE.
Forward mode (perturb parameters, see the change in the solution):
psolve(problem, requires_grad = TRUE)
delta(a) <- da # perturbation of parameter a
derivative(problem) # propagate forward
delta(x) # resulting change in variable xReverse mode (gradient of the solution with respect to parameters):
psolve(problem, requires_grad = TRUE)
backward(problem) # propagate backward
gradient(a) # d(solution) / d(a)The chain rule is wired through the Dgp2Dcp (log/exp)
and Complex2Real reductions, so geometric and complex
problems differentiate too. The derivative API is backed by the optional
diffcp R package. See the Derivatives
examples and Sensitivity
Analysis.
Bounds propagation and richer variable bounds
get_bounds() now works on any
expression, not just variables, propagating interval bounds
through affine, elementwise, and piecewise-linear atoms:
x <- Variable(3, bounds = list(-1, 2))
get_bounds(A %*% x + b) # bounds propagated through the affine map
get_bounds(abs(x)) # and through atomsVariable bounds may also be sparse Matrix
objects or symbolic bounds involving
Parameters; symbolic bounds are enforced at solve time and
update on DPP re-solves. Positive (DGP) variables accept numeric
and parametric bounds under gp = TRUE.
New atoms and DPP refinements
-
convolve()— the (numpy-style) name for the 1-D discrete-convolutionconv()atom; falls through tostats::convolve()on numeric input. -
is_dpp()gains acontextargument ("dcp"or"dgp"), matching CVXPY’sis_dpp(context = ...).
Solvers
- CPLEX now solves LP / SOCP / MI-LP / MI-SOCP through the conic path.
- Native variable bounds: HiGHS, Gurobi, CPLEX, XPRESS, PIQP, and SCIP now consume dense numeric variable bounds directly (including parametric bounds for HiGHS), avoiding extra bound constraints and speeding up DPP re-solves.
Bug fixes (also affected 1.8.x)
-
problem_data()/get_problem_data()now take an explicitgpargument; previouslygp = TRUEpassed through...was silently ignored, compiling a geometric program as a DCP problem. -
psolve()now takes explicitenforce_dppandignore_dpparguments, matching CVXPY’ssolve(); previously they were silently swallowed by....
CVXR 1.8.x
Complete Rewrite Using S7
CVXR 1.8.x is a ground-up rewrite using R’s S7 object system, designed to be isomorphic with CVXPY 1.8.2 for long-term maintainability. It is approximately 4–5x faster than the previous S4-based release. This section summarizes the key changes from CVXR 1.x that may affect users.
New Features
- S7 class system replaces S4 for all expression, constraint, and problem classes. Significantly faster construction and method dispatch.
- 15 solvers: CLARABEL (default), SCS, OSQP, HiGHS, MOSEK, Gurobi, GLPK, GLPK_MI, ECOS, ECOS_BB, CPLEX, CVXOPT, PIQP, SCIP, and XPRESS.
-
Mixed-integer programming via GLPK_MI, ECOS_BB,
Gurobi, CPLEX, HiGHS, SCIP, or XPRESS (
boolean = TRUEorinteger = TRUEinVariable()). -
Parameter support via
Parameter()class andEvalParamsreduction. - 50+ atom classes covering LP, QP, SOCP, SDP, exponential cone, and power cone problems.
- DPP (Disciplined Parameterized Programming) for efficient parameter re-solve with compilation caching.
-
DGP (Disciplined Geometric Programming) via
psolve(prob, gp = TRUE). -
DQCP (Disciplined Quasiconvex Programming) via
psolve(prob, qcp = TRUE). -
Complex variable support via
Variable(n, complex = TRUE). - Warm-start support for several solvers (OSQP, SCS, Gurobi, MOSEK, CLARABEL, HiGHS).
-
Matrix package interoperability via
as_cvxr_expr(). Matrix package objects (dgCMatrix,dgeMatrix,dsCMatrix,ddiMatrix,sparseVector) use S4 dispatch which preempts S7/S3, so they cannot be used directly with CVXR operators. Wrapping withas_cvxr_expr()converts them to CVXRConstantobjects while preserving sparsity (unlikeas.matrix()which densifies). Base Rmatrixandnumericobjects work natively without wrapping.
New solve interface
The primary solve function is now psolve(), which
returns the optimal value directly:
library(CVXR)
x <- Variable(2)
prob <- Problem(Minimize(sum_squares(x)), list(x >= 1))
opt_val <- psolve(prob) # returns optimal value directly
x_val <- value(x) # extract variable value
prob_status <- status(prob) # check statusThe old solve() still works but returns a
backward-compatible list:
result <- solve(prob)
result$value # optimal value
result$getValue(x) # variable value (deprecated)
result$status # problem statusBreaking Changes from CVXR 1.x
API changes
| Old API | New API |
|---|---|
solve(problem) |
psolve(problem) |
result$getValue(x) |
value(x) |
result$value |
return value of psolve()
|
result$status |
status(problem) |
result$getDualValue(con) |
dual_value(con) |
problem_status(prob) |
status(prob) |
problem_solution(prob) |
solution(prob) |
get_problem_data(prob, solver) |
problem_data(prob, solver) |
Axis parameter changes
The axis parameter now uses R’s apply()
convention (1-based indexing):
| Old CVXR | New CVXR | Meaning |
|---|---|---|
axis = 1 |
axis = 1 |
Row-wise reduction (unchanged) |
axis = 2 |
axis = 2 |
Column-wise reduction (unchanged) |
axis = NA |
axis = NULL |
All entries |
Passing axis = 0 now produces an informative error with
migration guidance.
PSD constraints
PSD constraints use PSD(A - B) instead of
A %>>% B (though %>>% and
%<<% operators are still available for backward
compatibility).
Solver changes
- Removed: CBC
- Added: HiGHS (LP, QP, MILP), Gurobi (LP, QP, SOCP, MIP), CVXOPT (LP, SOCP), PIQP (QP), SCIP, and XPRESS
- Default solver: CLARABEL (replaces ECOS)
Supported solvers
| Solver | R Package | Type | Problem Classes |
|---|---|---|---|
| CLARABEL | clarabel |
Conic | LP, QP, SOCP, SDP, ExpCone, PowCone |
| SCS | scs |
Conic | LP, QP, SOCP, SDP, ExpCone, PowCone |
| MOSEK | Rmosek |
Conic | LP, QP, SOCP, SDP, ExpCone, PowCone |
| ECOS | ECOSolveR |
Conic | LP, SOCP, ExpCone |
| ECOS_BB | ECOSolveR |
Conic | LP, SOCP, ExpCone + MI |
| GUROBI | gurobi |
Conic/QP | LP, QP, SOCP, MI |
| GLPK | Rglpk |
Conic | LP |
| GLPK_MI | Rglpk |
Conic | LP, MILP |
| HIGHS | highs |
Conic/QP | LP, QP, MILP |
| CVXOPT | cccp |
Conic | LP, SOCP |
| OSQP | osqp |
QP | LP, QP |
| CPLEX | Rcplex |
Conic/QP | LP, QP, SOCP, MI |
| PIQP | piqp |
QP | LP, QP |
| SCIP | scip |
Conic | LP, MILP, SOCP, MI-SOCP |
| XPRESS | xpress |
Conic/QP | LP, QP, SOCP, MI |
Smooth nonlinear programs additionally use the IPOPT and
UNO NLP solvers (see CVXR
1.9.1).
New Atoms and Functions
Convenience atoms
| Function | Description |
|---|---|
ptp(x) |
Peak-to-peak (range): max(x) - min(x)
|
cvxr_mean(x) |
Arithmetic mean along an axis |
cvxr_std(x) |
Standard deviation |
cvxr_var(x) |
Variance |
vdot(x, y) |
Vector dot product (inner product) |
cvxr_outer(x, y) |
Outer product of two vectors |
inv_prod(x) |
Reciprocal of product of entries |
loggamma(x) |
Elementwise log of gamma function |
log_normcdf(x) |
Elementwise log of standard normal CDF |
cummax_expr(x) |
Cumulative maximum along an axis |
dotsort(X, W) |
Weighted sorted dot product |
Other new atoms
-
perspective(f, s)for perspective functions -
FiniteSet(expr, values)constraint for discrete optimization -
ceil_expr(),floor_expr()for DQCP problems -
condition_number(),gen_lambda_max(),dist_ratio()for DQCP
Backward-Compatibility Aliases
-
tv()is deprecated; usetotal_variation()(still works but warns once) -
norm2(x)is deprecated; usep_norm(x, 2)(still works but warns once) -
multiply(x, y)is deprecated; usex * yfor elementwise multiplication - Old
solve()still works and returns a compatibility list - Old function names (
problem_status,getValue, etc.) still work but emit once-per-session deprecation warnings
Migration Guide
To migrate code from CVXR 1.x to 1.8.x:
Replace
result <- solve(problem)withopt_val <- psolve(problem)Replace
result$getValue(x)withvalue(x)Replace
result$valuewith the return value frompsolve()Replace
result$statuswithstatus(problem)Replace
result$getDualValue(con)withdual_value(con)Update solver names:
"ECOS"→"CLARABEL","GLPK"→"HIGHS"Update
axisarguments:axis = NA→axis = NULL(row/column axis values 1 and 2 are unchanged)Replace
A %>>% BwithPSD(A - B)if desiredWrap Matrix package objects with
as_cvxr_expr()before using them in CVXR expressions (e.g.,as_cvxr_expr(A) %*% xinstead ofA %*% xwhenAis adgCMatrixor other Matrix class). This preserves sparsity. Base R matrices need no wrapping.-
Dimension-preserving operations. CVXR 1.8 preserves 2D shapes throughout, matching CVXPY. In particular, axis reductions like
sum_entries(X, axis = 2)now return a proper row vector of shape(1, n)rather than collapsing to a 1D vector. When comparing such a result with an R numeric vector (which CVXR treats as a column), you may need to uset()ormatrix(..., nrow = 1)to match shapes:## Old (worked in CVXR 1.x because axis reductions were 1D): sum_entries(X, axis = 2) == target_vec ## New (wrap target as row vector to match the (1, n) shape): sum_entries(X, axis = 2) == t(target_vec)Similarly, if you extract a scalar from a CVXR result and need a plain numeric value, use
as.numeric()to drop the matrix dimensions.
CRAN Submission Tip
If you encounter issues involving the Rmosek package
while submitting your package to CRAN, include the following code in
<your_pkg>/R/zzz.R to resolve the issue.
## Content of <your_pkg>/R/zzz.R
.onLoad <- function(libname, pkgname) {
CVXR::exclude_solvers("MOSEK")
}
.onUnload <- function(libname, pkgname) {
CVXR::include_solvers("MOSEK")
}Further Reading
- CVXR website — worked examples
- Package reference — full API documentation
- CVXPY documentation — mathematical framework
- Fu, Narasimhan, and Boyd (2020). “CVXR: An R Package for Disciplined Convex Optimization.” Journal of Statistical Software, 94(14). doi:10.18637/jss.v094.i14