Calling CVX from R – an R package

The problem

As part of my research, I find that I am often writing R code for solving specific convex optimization problems. In doing so, I often want to quickly check on small problems whether I am getting the right answer. CVX is a tool by Michael Grant and Stephen Boyd that makes it easy to solve general convex problems, and the syntax to input such problems is simple and straightforward. In this sense, CVX is the ideal tool for quickly confirming that my code is working. The trouble is that I work in R, but CVX is in Matlab.

New: If you prefer Julia to MATLAB, then consider using Convex.jl via this new R package: convexjulia.

My low-tech solution

I have written an R package CVXfromR with a function CallCVX, that lets you call CVX from R. You pass CallCVX four things:

An example: The Lasso

We begin by generating some data in R.

n <- 50
p <- 10
x <- matrix(rnorm(n * p), n, p)
beta <- rnorm(p)
y <- x %*% beta + 0.1 * rnorm(n)

Now suppose we would like to perform the Lasso using CVX. We begin by loading the package and giving the path of the directory containing the file cvx_setup.m:

library(CVXfromR)
setup.dir <- "change/this/to/your/cvx/directory"

We are now ready to send off an optimization problem to CVX:

cvxcode <- paste("variables b(p)",
                 "minimize(square_pos(norm(y - x * b, 2)) / 2 + lam * norm(b, 1))",
                 sep=";")
lasso <- CallCVX(cvxcode, const.vars=list(p=p, y=y, x=x, lam=2),
                 opt.var.names="b", setup.dir=setup.dir)

The output contains an optimal point, the optimal value, the number of seconds elapsed for the call to CVX (not counting the time opening Matlab and transferring data between R and Matlab):

> names(lasso)
[1] "b"       "cvx_optval" "time"       "command"

If there is an error in the Matlab code you have passed, it will leave you in Matlab (useful for diagnosing the problem). Typing exit brings you back into R.

New feature: To solve this problem for a sequence of values of the tuning parameter, one no longer needs to wrap CallCVX in a loop. Rather, use CallCVX.varyparam:

lasso <- CallCVX.varyparam(cvxcode, const.vars=list(p=p, y=y, x=x), tuning.param=list(lam=seq(0.1, 1, length=20)),
                           opt.var.names="b", setup.dir=setup.dir)

The returned value b would be a list of length 20, giving optimal points for each value of the tuning parameter.

Requirements

Download

Here is a recent version of the package. The most up-to-date version is available on github. (Thanks to Stefan Avey for contributing an improvement.)

New: CVXfromR now available on Windows. Click here for Windows version.

How does it work?

My approach is very low-tech in the sense that it actually just forms a very long string that is passed to Matlab through a call to the command line. It passes data from R to Matlab and then back to R by saving temporary files.

Future

I see this as a temporary solution until someone actually writes CVX for R. I look forward to that, but in the meantime, CallCVX works well for me.