Disciplined Convex Optimization
Overview
An object-oriented modeling language for disciplined convex programming (DCP) as described in Fu, Narasimhan, and Boyd (2020, doi:10.18637/jss.v094.i14). It allows the user to formulate convex optimization problems in a natural way following mathematical convention and DCP rules. The system analyzes the problem, verifies its convexity, converts it into a canonical form, and hands it off to an appropriate solver to obtain the solution. This version uses the S7 object system for improved performance and maintainability.
Changed results
These fix wrong answers, so code that relied on the old results will see
different numbers.
- GUROBI solved quadratic objectives with cross terms (e.g.
quad_form(w, Sigma)) with every cross term halved. Gurobi now receives the full matrix, as in CVXPY. Present in 1.9.2. - CVXOPT returned wrong answers on problems with no inequality constraints (feasible equality-constrained problems were reported infeasible) and reported unbounded problems as optimal. These now solve correctly or fail with a solver error, as in CVXPY.
- GUROBI second-order-cone dual values had the wrong sign; they now agree with CVXPY and with every other solver.
Show all changes in 1.9.3Hide the rest of the changes in 1.9.3
cvxr_norm(X, p)andnorm(X, type)now agree with base R'snorm()and CVXPY on matrices: with noaxis,p = 1,2andInfare the maximum absolute column sum, the largest singular value and the maximum absolute row sum. They were entrywise; usecvxr_norm(X, "fro")ornorm1(X)for those.- A row vector is a 1 x n matrix, as in base R, so its 1- and Inf-norms are the other way round from before.
- Any other
pon a matrix or row vector is now an error, "Unsupported matrix norm.", as in CVXPY; usep_norm(x, p)for the entrywise norm. norm()on an expression accepts every base R type ("O","M"and"E"failed, and"I"was the largest absolute entry). With notypeit is the spectral norm ("2"), as in CVXPY.gmatmul(A, X)with aParameterin bothAandXgave a wrong answer undergp = TRUE, and parameter substitution rebuilt it withAandXswapped. Both fixed (CVXPY 1.9.3 still has the swap).x / Awith a matrix or vectorAdivided every entry ofxbyA[1, 1]. It now divides entrywise, as in CVXPY. Division by a scalar is unchanged. Present in 1.9.2.- Constants built from Matrix classes other than
dgCMatrixgave wrong answers or errors: a unitDiagonal(n)was read as all zeros, soquad_form(x, Diagonal(n))was unbounded, and symmetric, triangular, triplet, pattern and logical sparse matrices failed in canonicalization. Every sparse input is now stored as a general doubledgCMatrix, as in CVXPY, and a logical matrix constant keeps its shape instead of becoming a column. Present in 1.9.2. - A sparse
boundsmatrix was applied only at its stored entries, so a symmetric (dsCMatrix) bound on a dense variable left half the entries unbounded and a triplet matrix with repeated entries used the first copy. As in CVXPY, a sparse bound is now accepted only on asparsityvariable with the same pattern, and repeated entries are summed. Solvers that take variable bounds natively (HiGHS, GUROBI, SCIP, XPRESS) now receive such bounds as bounds rather than as constraints. Present in 1.9.2. - A warm re-solve with CLARABEL or OSQP after a parameter became zero (or nonzero) pushed the new coefficients into the solver's old sparsity pattern, returning the previous optimum with status optimal, or an OSQP error. Both now start a fresh solver when the pattern changes, as PIQP already did. Present in 1.9.2.
- The cached DGP, DQCP and problem-level curvature queries ignored whether a DPP check was running, so a DGP problem with parameters could be reported DPP and solved with wrong solver data. All caches are now keyed on the DPP scope, as CVXPY's are.
perspective()of a function of asymmetric,PSDorNSDmatrix variable of size 3 or more returned a wrong optimum.sum_entries(x, axis = 2)of a one-row expression gave wrong results or crashed R. Present in 1.9.2.%*%with a scalar operand that does not conform (2 %*% xfor a 2 x 3x) or a non-conforming 1 x 1 operand built a product that gave a scalar product or crashed R. Both are now errors, as in base R; use*to multiply by a scalar. A scalar operand that conforms (x %*% 2for a 3 x 1x) is a product, as in base R.x / dwith shapes that do not broadcast, such as a 2 x 3xand a length-3d, recycled the divisor silently. It is now an error, as in CVXPY; a row or column divisor still broadcasts.value()of a sum, a product or an index of a sparse-matrix constant failed with "non-conformable arrays" or "subscript out of bounds", and a sum of two sparse constants came back flattened to one column. These now evaluate; a mixed sparse and dense result is a base matrix, a sparse one stays sparse.sum(),max(),min()andprod()of an expression now honoraxisandkeepdims, as in CVXPY. A namedaxiswas taken as one more operand, sosum(x, axis = 2)returnedsum(x + 2). Any other name labels an operand, as inbase::sum(), sosum(a = x)anddo.call(sum, parts)with a named list work as before.sum(),prod(),max()andmin()with more than one operand now mean what they mean in base R: each operand is reduced on its own and the results combined, sosum(x, 2)issum(x) + 2andmax(x, y)is one scalar, the largest entry of either. They weresum(x + 2),prod(x * y)and the elementwise maximum and minimum; usemax_elemwise()andmin_elemwise()for those.matrix_trace(A * B)returned the trace of the matrix product (CVXPY 1.9.3, #3492).cumsum(X)of a matrix expression is now column-wise, as in CVXPY and ascumprod()andcummax()already were;value()and the solver used to disagree.cumsum_axis(X, axis = NULL)gives all entries in column-major order as a column.lambda_sum_largest(X, k)accepts a fractionalk, as CVXPY does;kwas silently truncated.- Bounds through
min_elemwise()andmax_elemwise()with operands of different shapes now broadcast as NumPy does; a row operand was permuted. derivative()andbackward()through a Hermitian variable or parameter of size 4 or more had imaginary entries transposed.backward()through asparsityvariable returned garbage, and on the NLP path the bounds of asparsityvariable were dropped. A recovered variable value is now projected onto its attribute (anonneg-1e-9 reads back as 0), as in CVXPY.psolve(solver = "CLARABEL", warm_start = TRUE)re-solves from scratch when the cones changed (e.g. a parametric power-cone exponent), instead of returning the previous optimum. CVXPY 1.9.3 still has this defect.- A complex variable declared
PSD/NSDlost its cone (#3342), and one declareddiagor with asparsitypattern solved as dense (CVXPY 1.9.3 still ignores those). Both are now enforced. conv(),cumsum()andkron()were treated as log-log affine, so a geometric program containing them was accepted and could solve to a wrong value. They are now not DGP, as in CVXPY, and such a problem is rejected.- Calling
problem_data()(orget_problem_data()) on a geometric program between two solves made the next solve after a parameter change return the previous optimum.problem_data()now goes through the same compile cache aspsolve(), as in CVXPY. max_elemwise()andmin_elemwise()of a column and a row recycled instead of broadcasting, sopsolve()returned a wrong objective and a second solve failed.log(x, base)on an expression ignoredbaseand gave the natural log. It now honorsbase, which must be a positive number other than 1.outer(x, y, FUN)on an expression ignoredFUNand gave the product. AnyFUNother than"*"is now an error.x[NULL, ]andx[NULL]on an expression returned all ofx. ANULLsubscript is now an error.x[c(TRUE, NA, FALSE), ]on an expression dropped theNA. AnNAor character subscript is now a clear error instead of an obscure one.diag(x, nrow)on an expression ignorednrow.nrow,ncolandnamesare now errors there; the offset isk.log1p(x)on an expression is now thelog1patom instead oflog(x + 1), so it is accurate near 0 and keeps the sign ofx.
New features
geo_mean()accepts an argument of any shape and gainsaxisandkeepdims(CVXPY 1.9.3, #3493).cvxr_var()supportsaxisandkeepdims, likecvxr_mean()andcvxr_std()(#3496).cvxr_norm(X, "nuc")returns the nuclear norm (it errored).- Exact
geo_mean(x, approx = FALSE), and anyPowConeNDconstraint, now solve on SCS and MOSEK, not just Clarabel.PowConeND()with a row-vectorz, or a 1 x nWwithaxis = 1, now works and has correct duals. perspective(f, s)wherefneeds a positive semidefinite cone (for examplelambda_max()orsigma_max()) now solves on Clarabel, SCS and MOSEK.grad()works forpartial_optimize()expressions andlambda_sum_largest(), and is correct for complex arguments ofnorm_nuc(),sigma_max(),quad_form(),quad_over_lin()andmatrix_frac().indicator()andpartial_optimize()expressions now have bounds, as in CVXPY:(0, Inf)for an indicator and unbounded for a partial problem.- A quadratic objective over a
symmetric,PSD,NSD,diagorsparsityvariable now solves on QP-capable solvers (#3384), andquad_over_lin()/sum_squares()with anaxistake the QP path, so OSQP accepts them. - DNLP (
psolve(..., nlp = TRUE)) now needssparsediff (>= 0.6.1)and consequences thereof. It also acceptsNonNeg(),NonPos()andZero()constraints, which it used to abort on. - New
curvatures(),log_log_curvature()andis_diag(), as CVXPY'sExpression.curvatures,Expression.log_log_curvatureandLeaf.is_diag(). curvature()now reports log-log and quasi curvature (e.g."LOG-LOG CONVEX","QUASILINEAR") instead of"UNKNOWN", as in CVXPY.
DPP, DGP and DQCP
psolve()now checks that everyParameterhas a value before it starts any solve, as CVXPY does.psolve(gp = TRUE)now checks variable bounds when deciding whether a parameterized problem is DPP, as CVXPY does, and requires a conic solver.is_dpp()is now one DCP pass inside the DPP scope, as in CVXPY, instead of that pass plus a recursion over every argument.- These are no longer DPP, as in CVXPY:
quad_over_lin(x, p)with aParameterdenominator (#2433), aPowCone3D()/PowConeND()with aParameterexponent, anddotsort(x, W)with a non-affine parametricW.gmatmul(A, X)requires a parametricAto be theParameteritself.cumsum()of aParameteris DPP (#3398). psolve(requires_grad = TRUE)checks match CVXPY: a non-DPP problem is aDPPError,qcp = TRUEis refused, andsolver = "SCS"routes to DIFFCP.- DQCP bisection now follows CVXPY: no extra solve at the upper end of an automatically found interval, sub-solve warnings reach the user, a failed query point warns and bisection continues, and its aborts carry class
SolverError.
Solvers
- Solver selection now follows CVXPY 1.9: the solver is chosen from the problem's structure first, and its interface (QP or conic) follows. The commercial-first default covers QPs and mixed-integer QPs, SCIP solves mixed-integer QPs, a named HiGHS, Gurobi, CPLEX or Xpress solves an LP through its conic interface, and falling back to a non-default solver warns. ECOS_BB is never chosen unless named.
- When no installed (or non-excluded) solver can be used, the error now reads "No installed solver could handle this problem.", as in CVXPY.
psolve(solver_path = ...)forwards everypsolve()argument to each attempt (enforce_dpp,ignore_dppandnlpwere dropped), and only aSolverErrormoves on to the next solver, as in CVXPY. The conditions CVXPY raises asSolverErrornow carry that class in R too.- MOSEK: the status comes from the solution status, as in CVXPY, so a termination code such as an iteration or time limit is no longer an error by itself. The simplex optimizers work, and
bfs = TRUEandsave_file = <path>are accepted. - HiGHS: options may be nested in a
highs_optionslist, as in CVXPY, and an option HiGHS rejects is an error instead of being dropped. A stop onmip_max_improving_solsreturns the incumbent with statususer_limit. - Gurobi:
warm_start = TRUEseeds the start point from the variables' values,save_filewrites the model, andenvis rejected, as in CVXPY.solver_stats(prob)@num_itersis 0 instead ofNULLwhen presolve finished the problem. - CPLEX:
reoptimize = TRUEre-solves with presolve off on "infeasible or unbounded", as in CVXPY;solve_timeis set; unknown options abort. A continuous problem with a second-order cone now returns dual values (all were missing), as in CVXPY. - SCS: an infeasible solve exposes the infeasibility certificate through
dual_value()(#3197), andextra_statsis the full SCS result. solver_stats(prob)@extra_statsnow carries the raw solver result for OSQP, ECOS, ECOS_BB, Gurobi, DIFFCP, HiGHS and PIQP, as CVXPY does, andsolution(prob)holds only the problem's own variables.- PIQP:
backend = "dense"builds a dense model (it was silently sparse). - XPRESS: a
write_mpspath that cannot be written is an error (it was silently skipped), and a failed optimization reports the solver's message as a warning before the solver-error status. - GLPK_MI: an infeasible mixed-integer problem has status
infeasible, as in CVXPY; it failed with a solver error. GLPK's presolve is now on by default (passpresolve = FALSEto turn it off). - Solving no longer advances R's random number stream. Compilation drew from it (sixteen uniforms per expression node, for an internal debugging label), so random draws after
psolve()differed from the same draws without the solve. Present in every earlier version.
Errors, warnings and other changes
diag()on an ordinary R matrix or vector now behaves exactly as base R'sdiag():diag(nrow = 3)andnames = FALSEwork, andk(expressions only) is an error instead of being ignored.norm(A)on an ordinary R matrix without atypenow uses base R's default one-norm ("O"), not the spectral norm; expressions keep"2".convolve()on ordinary numeric vectors now returns exactlystats::convolve()'s result, with itsconjandtypearguments, as the 1.9.2 NEWS promised; expressions still get the numpy-style convolution.sd()andvar()on an expression arecvxr_std()andcvxr_var()(ddof 0, as in CVXPY);na.rm,useand a second variableynow give a clear error instead of an obscure one.mean()on an expression iscvxr_mean();trimandna.rmnow give a clear error, and an axis other than 1 or 2 (such as1.5) is an error instead of being truncated.- A non-scalar constant exponent (
x^c(1, 2),power(x, c(1, 2))) is now a clear error; withapprox = FALSEit was silently accepted. - New
cvxr_power(), the same function aspower().power()masks the unrelatedstats::power(), aglm()link, so with CVXR attached writestats::power()in aglm()family. - Variable
boundsaccept a 1-d array, asparseVectorand a sparse matrix with unsorted row indices, whichConstant()already accepted. power(x, p)now takes its sign, curvature, domain, value and printed name frompas written, as CVXPY does, rather than from the rational approximation used to solve it.- Calling
NonPos(expr)explicitly now warns, once per session, that it is deprecated in favor of operator overloading (expr <= 0) orNonNeg(-expr), in CVXPY's words and with classCvxpyDeprecationWarning. - Now errors, as in CVXPY: a negative
axis; anaxiswithcvxr_norm(X, "fro")or"nuc"(#3501); a complex variable declarednonneg,nonpos,pos,negor withbounds, which were silently ignored (#3342);partial_optimize()of a complex inner problem. - Whether a constant matrix is symmetric, Hermitian or skew-symmetric is now decided with NumPy's
allclosetolerance (relative 1e-5, absolute 1e-8), as in CVXPY;quad_form(x, P)used to reject aPthat CVXPY accepts. - Smaller alignments with CVXPY 1.9.3 in
get_bounds(),grad()anddomain()of several atoms,dual_cone(),is_symmetric()ofRe(X),constr_size(),is_dpp()with an unsupported context, interval bounds of matrix products, andis_quadratic()of `
The NEWS section is longer than shown here.
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK12 OK2026-04-25
- NOTE11 OK, 3 NOTE2026-04-22
- ERROR10 OK, 3 NOTE, 1 ERROR2026-04-18
Show 2 earlier changesHide 2 earlier changes
- NOTE11 OK, 3 NOTE2026-03-12
- ERROR10 OK, 3 NOTE, 1 ERROR2026-03-10
Documentation
- Help pages
- 299 (87 internal)includes a package overview page
- Examples that run
- 100%32 run in a plain check
- Exported functions with examples
- 15%
- Documented parameters
- 98%
- Return-value docs
- 100%
- Help pages citing references
- 0%
- Introduction to CVXR HTML
- What's New in CVXR HTML
Downloads
Repository
- PRs merged (all time)
- 90%
- Median days to close, 50 most recently updated closed issues
- 532
- Median days to close, 50 most recently updated closed PRs
- 0
Stars over time
Forks over time
Releases over time
Issues over time
PRs over time
Commits over time
6 development-tooling and community-health practices detected across 3 families in the upstream repository
Checks run against github.com/cvxgrp/cvxr on 2026-10-18.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-08-24
pkgdown site last built 2026-03-01, before release 1.9.3 (2026-10-19)
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-02-27Pull request it wrote: opened by a project memberCommits: at least 44 crediting it in the message
- Claude Opus 4.643 commits · Feb to Apr 2026
Dependencies
Installing CVXR adds 12 packages (12 with compiled code, 14 MB of source tarballs). Heaviest: clarabel 5.7 MB, Rcpp 1.8 MB, scs 1.8 MB.
Show all 40 packagesHide all 40 packages
Code & Tests
Datasets
People & History
Pick two releases to compare their code metrics.
- 1.9.3Latest2026-10-19 · current release · diff ↗ ·
added 4 exports
curvatures, cvxr_power, is_diag, log_log_curvature - 1.9.2
- 1.9.12026-06-09 · diff ↗ ·
added 38 exports
delta<-, gradient<-, label<-, sample_bounds<-, COPT_SOLVER, CallbackParam, DIFFCP_SOLVER, IPOPT_SOLVER, KNITRO_SOLVER, PartialProblem, SizeMetrics, UNO_SOLVER, backward, convolve, delta, derivative, format_labeled, get_bounds, gradient, is_atom_smooth, is_dnlp, is_linearizable_concave, is_linearizable_convex, is_smooth, label, normcdf, param_backward, param_dict, param_forward, param_id_map and 8 more - RR 4.6.0 released · 2026-04-24
- 1.8.2
- 1.8.12026-03-06 · diff ↗ ·
removed 56 exports
constraints<-, dual_value<-, objective<-, CBC_CONIC, CLARABEL, CPLEX_CONIC, CPLEX_QP, CallbackParam, ECOS, ECOS.dims_to_solver_dict, ECOS_BB, GLPK, GLPK_MI, GUROBI_CONIC, GUROBI_QP, MOSEK, OSQP, SCS, add_to_solver_blacklist, as.Constant, atoms, canonicalize, constr_value, cummax_axis, domain, get_data, get_id, get_np, get_sp, grad and 26 moreadded 107 exports
And, CLARABEL_SOLVER, CPLEX_SOLVER, CVXOPT_SOLVER, DiagMat, DiagVec, ECOS_BB_SOLVER, ECOS_SOLVER, Equality, ExpCone, FiniteSet, GLPK_MI_SOLVER, GLPK_SOLVER, GUROBI_SOLVER, HIGHS_SOLVER, INFEASIBLE, INFEASIBLE_INACCURATE, INFEASIBLE_OR_UNBOUNDED, Inequality, MOSEK_SOLVER, NonNeg, NonPos, Not, OPTIMAL, OPTIMAL_INACCURATE, OSQP_SOLVER, Or, PIQP_SOLVER, PSD, PowCone3D and 77 more - RR 4.5.0 released · 2025-04-11
- 1.0-152024-11-07 · diff ↗
- 1.0-14
- 1.0-132024-06-01 · diff ↗
- RR 4.4.0 released · 2024-04-24
- 1.0-122024-02-02 · diff ↗
- RR 4.3.0 released · 2023-04-21
- 1.0-112022-10-30 · diff ↗
- RR 4.2.0 released · 2022-04-22
- 1.0-102021-11-10 · diff ↗
Show 18 earlier eventsHide 18 earlier events
- RR 4.1.0 released · 2021-05-18
- 1.0-92021-01-19 · diff ↗
- 1.0-82020-09-13 · diff ↗
- RR 4.0.0 released · 2020-04-24
- 1.0-12020-04-02 · diff ↗ ·
added 3 exports
add_to_solver_blacklist, remove_from_solver_blacklist, set_solver_blacklist - 1.02020-02-02 · diff ↗ ·
removed 20 exports
Bool, GUROBI, Int, LPSOLVE, NonNegative, Semidef, SemidefUpperTri, Symmetric, SymmetricUpperTri, affine_prod, exp_capable, get_gurobiglue, get_mosekglue, is_negative, is_positive, lp_capable, mul_elemwise, sdp_capable, socp_capable, squareadded 44 exports
dual_value<-, CBC_CONIC, CPLEX_CONIC, CPLEX_QP, ECOS.dims_to_solver_dict, GLPK_MI, GUROBI_CONIC, GUROBI_QP, OSQP, atoms, constr_value, cummax_axis, dual_value, eye_minus_inv, is_atom_log_log_affine, is_atom_log_log_concave, is_atom_log_log_convex, is_complex, is_dgp, is_hermitian, is_imag, is_log_log_affine, is_log_log_concave, is_log_log_constant, is_log_log_convex, is_mixed_integer, is_neg, is_nonneg, is_nonpos, is_nsd and 14 more - 0.99-72019-11-07 · diff ↗
- 0.99-62019-06-02 · diff ↗
- 0.99-52019-05-13 · diff ↗
- RR 3.6.0 released · 2019-04-26
- 0.99-42019-03-13 · diff ↗
- 0.99-32019-02-20 · diff ↗
- 0.99-22018-11-06 · diff ↗
- 0.992018-05-26 · diff ↗ ·
added 8 exports
GLPK, GUROBI, LPSOLVE, MOSEK, get_gurobiglue, get_mosekglue, get_np, get_sp - RR 3.5.0 released · 2018-04-23
- 0.95
- 0.94-42017-11-20
- RR 3.4.0 released · 2017-04-21
Package metadata
- First published
- 2017-11-20
- Total releases
- 24 / 9 yrs
- License
- Apache License 2.0 | file LICENSE OSI
- Additional repositories
- bnaras.r-universe.dev, bnaras.github.io
- Minimum R
- ≥ 4.3.0
- Bundled data
- 16 KB / 3 files
- Download size
- 847 KB
Cite
Cite this package
Run in R for the authors' entry:
citation("CVXR")The package provides a citation file, so citation() returns the authors' own entry.
It points to 10.18637/jss.v094.i14.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-21, which the citation names so these numbers can be found later. More on citing and the projects behind them.