CVXR is an R package that provides an object-oriented
modeling language for convex optimization, similar to CVXPY for Python. It allows you to
formulate and solve convex optimization problems in a natural
mathematical syntax.
Consider a simple linear regression problem where we want to estimate parameters using a least squares criterion.
We generate synthetic data where we know the true model:
\[ Y = X\beta + \epsilon \]
where \(Y\) is a \(100 \times 1\) vector, \(X\) is a \(100 \times 10\) matrix, \(\beta = (-4, -3, \ldots, 5)^\top\) is a \(10 \times 1\) vector, and \(\epsilon \sim N(0, 1)\).
set.seed(123)
n <- 100
p <- 10
beta <- -4:5
X <- matrix(rnorm(n * p), nrow = n)
Y <- X %*% beta + rnorm(n)Using base R, we can estimate \(\beta\) via lm:
The same problem can be expressed as:
\[ \underset{\beta}{\text{minimize}} \quad \|Y - X\beta\|_2^2 \]
In CVXR, this translates directly:
library(CVXR)
#>
#> Attaching package: 'CVXR'
#> The following objects are masked from 'package:stats':
#>
#> power, sd, var
#> The following objects are masked from 'package:base':
#>
#> norm, outer
betaHat <- Variable(p)
objective <- Minimize(sum((Y - X %*% betaHat)^2))
problem <- Problem(objective)
result <- psolve(problem, solver = "CLARABEL")The optimal value and estimated coefficients:
cat("Optimal value:", result, "\n")
#> Optimal value: 97.84759
cbind(CVXR = round(value(betaHat), 3),
lm = round(coef(ls.model), 3))
#> lm
#> X1 -3.920 -3.920
#> X2 -3.012 -3.012
#> X3 -2.125 -2.125
#> X4 -0.867 -0.867
#> X5 0.091 0.091
#> X6 0.949 0.949
#> X7 2.076 2.076
#> X8 3.127 3.127
#> X9 3.961 3.961
#> X10 5.135 5.135The real power of CVXR is the ability to add constraints easily.
Suppose we know the \(\beta\)s should be nonnegative:
Now suppose \(\beta_2 + \beta_3 \le 0\) and all other \(\beta\)s are nonnegative:
A <- matrix(c(0, 1, 1, rep(0, 7)), nrow = 1)
B <- diag(c(1, 0, 0, rep(1, 7)))
constraint1 <- A %*% betaHat <= 0
constraint2 <- B %*% betaHat >= 0
problem <- Problem(objective, constraints = list(constraint1, constraint2))
result <- psolve(problem, solver = "CLARABEL", verbose = TRUE) ## verbose = TRUE for details
#> ────────────────────────────────── CVXR v1.8.1 ─────────────────────────────────
#> ℹ Problem: 1 variable, 2 constraints (QP)
#> ℹ Compilation: "CLARABEL" via CVXR::Dcp2Cone -> CVXR::CvxAttr2Constr -> CVXR::ConeMatrixStuffing -> CVXR::Clarabel_Solver
#> ℹ Compile time: 0.013s
#> ─────────────────────────────── Numerical solver ───────────────────────────────
#> ──────────────────────────────────── Summary ───────────────────────────────────
#> ✔ Status: optimal
#> ✔ Optimal value: 1287.63
#> ℹ Compile time: 0.013s
#> ℹ Solver time: 0.001s
round(value(betaHat), 3)
#> [,1]
#> [1,] 0.000
#> [2,] -2.845
#> [3,] -1.711
#> [4,] 0.000
#> [5,] 0.664
#> [6,] 1.178
#> [7,] 2.329
#> [8,] 2.414
#> [9,] 4.212
#> [10,] 4.948This demonstrates the chief advantage of CVXR: flexibility. Users can quickly modify and re-solve a problem, making the package ideal for prototyping new statistical methods. Its syntax is simple and mathematically intuitive.
CVXR supports multiple solvers:
installed_solvers()
#> [1] "CLARABEL" "SCS" "OSQP" "HIGHS" "MOSEK" "GUROBI"
#> [7] "GLPK" "GLPK_MI" "ECOS" "ECOS_BB" "CPLEX" "CVXOPT"
#> [13] "PIQP"You can specify a solver explicitly:
sessionInfo()
#> R version 4.5.2 (2025-10-31)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Tahoe 26.3.1
#>
#> Matrix products: default
#> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#>
#> time zone: America/Los_Angeles
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] CVXR_1.8.1
#>
#> loaded via a namespace (and not attached):
#> [1] slam_0.1-55 cli_3.6.5 knitr_1.51 ECOSolveR_0.6.1
#> [5] rlang_1.1.7 xfun_0.56 clarabel_0.11.2 gurobi_13.0-1
#> [9] otel_0.2.0 Rglpk_0.6-5.1 highs_1.12.0-3 cccp_0.3-3
#> [13] scs_3.2.7 S7_0.2.1 jsonlite_2.0.0 Rcplex_0.3-8
#> [17] backports_1.5.0 Rmosek_11.1.1 htmltools_0.5.9 sass_0.4.10
#> [21] gmp_0.7-5.1 piqp_0.6.2 rmarkdown_2.30 grid_4.5.2
#> [25] evaluate_1.0.5 jquerylib_0.1.4 fastmap_1.2.0 yaml_2.3.12
#> [29] lifecycle_1.0.5 compiler_4.5.2 codetools_0.2-20 Rcpp_1.1.1
#> [33] osqp_1.0.0 lattice_0.22-9 digest_0.6.39 R6_2.6.1
#> [37] bslib_0.10.0 checkmate_2.3.4 Matrix_1.7-4 tools_4.5.2
#> [41] cachem_1.1.0