IEEE CONTROL SYSTEMS LETTERS, VOL. 6, 2022 2653
Embedded Code Generation With CVXPY
Maximilian Schaller , Goran Banjac , Steven Diamond, Member, IEEE, Akshay Agrawal,
Bartolomeo Stellato
, Member, IEEE, and Stephen Boyd , Fellow, IEEE
Abstract—We introduce CVXPYgen, a tool for generating
custom C code, suitable for embedded applications, that
solves a parameterized class of convex optimization prob-
lems. CVXPYgen is based on CVXPY, a Python-embedded
domain-specific language that supports a natural syntax
(that follows the mathematical description) for specifying
convex optimization problems. Along with the C implemen-
tation of a custom solver, CVXPYgen creates a Python
wrapper for prototyping and desktop (non-embedded)
applications. We give two examples, position control of
a quadcopter and back-testing a portfolio optimization
model. CVXPYgen outperforms a state-of-the-art code gen-
eration tool in terms of problem size it can handle, binary
code size, and solve times. CVXPYgen and the generated
solvers are open-source.
Index Terms—Computational methods, embedded
systems, optimization.
I. INTRODUCTION
C
ONVEX optimization is used in many domains, includ-
ing signal and image processing [1], [2], control [3], [4],
and finance [5], [6], to mention just a few. A (parameterized)
convex optimization problem can be written as
minimize f
0
(x,θ)
subject to f
i
(x,θ) ≤ 0, i = 1,...,p
g
j
(x,θ) = 0, j = 1,...,r, (1)
where x ∈ R
n
is the optimization variable, f
0
is the objective
function to be minimized, f
1
,...,f
p
are the inequality constraint
functions, and g
1
...,g
r
are the equality constraint functions.
Manuscript received March 21, 2022; accepted April 21, 2022. Date
of publication May 6, 2022; date of current version May 16, 2022.
This work was supported in part by the European Research Council
(ERC) through the European Union’s Horizon 2020 Research and
Innovation Programme grant agreement under Grant 787845; in part
by the Stanford’s SystemX; and in part by the AI Chip Center for
Emerging Smart Systems (ACCESS). Recommended by Senior Editor
F. Dabbene. (Corresponding author: Maximilian Schaller.)
Maximilian Schaller and Goran Banjac are with the Department of
Information Technology and Electrical Engineering, ETH Zürich, 8092
Zürich, Switzerland (e-mail: mschaller@ethz.ch; gbanjac@ethz.ch).
Steven Diamond is with Gridmatic, Campbell, CA 95008 USA (e-mail:
steven@gridmatic.com).
Akshay Agrawal and Stephen Boyd are with the Department of
Electrical Engineering, Stanford University, Stanford, CA 94305 USA
(e-mail: akshayka@stanford.edu; boyd@stanford.edu).
Bartolomeo Stellato is with the Department of Operations Research
and Financial Engineering, Princeton University, Princeton, NJ 08544
USA (e-mail: bstellato@princeton.edu).
Digital Object Identifier 10.1109/LCSYS.2022.3173209
We require that f
0
,...,f
p
are convex functions, and g
1
,...,g
r
are affine functions [7]. The parameter θ ∈ R
d
specifies data
that can change, but is constant and given when we solve
an instance of the problem. We refer to the parameterized
problem (1) as a problem family; when we specify a fixed
value of θ , we refer to it as a problem instance.Weletx
denote an optimal point for the problem (1), assuming it exists.
The problem family can be specified using a domain-
specific language (DSL) for convex optimization. Such
systems allow the user to specify the functions f
i
and g
j
in a simple format that closely follows the mathematical
description of the problem. Examples include YALMIP [8]
and CVX [9] (in MATLAB), CVXPY [10] (in Python),
Convex.jl [11] and JuMP [12] (in Julia), and CVXR [13]
(in R). We focus on CVXPY, which provides an efficient way
of dealing with parameters, specifying problem families, not
just problem instances.
DSLs parse the problem description and translate (or canon-
icalize) it to an equivalent problem that is suitable for a solver
that handles some generic class of problems, such as linear
programs (LPs), quadratic programs (QPs), second-order cone
programs (SOCPs), semidefinite programs (SDPs), and others
such as exponential cone programs [7]. We focus on solvers
that are suitable for embedded applications, i.e., are single-
threaded, can be statically compiled, and do not make system
calls: OSQP [14] handles QPs, SCS [15] and ECOS [16]
handle cone programs that include SOCPs. After the canoni-
calized problem is solved, a solution of the original problem
is retrieved from a solution of the canonicalized problem.
It is useful to think of the whole process as a function that
maps θ, the parameter that specifies the problem instance,
into x
(θ), an optimal value of the variable. With a DSL,
this process consists of three steps. First the original problem
description is canonicalized to a problem in some standard
(or canonical) form; then the canonicalized problem is solved
using a solver; and finally, a solution of the original problem
is retrieved from a solution of the canonicalized problem.
Most of these DSLs are organized as parser-solvers, which
carry out the canonicalization each time the problem is solved
(with different parameter values). This simple setting is illus-
trated in Figure 1(a). We are interested in applications where
we solve many instances of the problem, possibly in an
embedded application with hard real-time constraints. For such
applications, a code generator makes more sense. A code
generator takes as input a description of a problem family,
and generates specialized solver source code for that specific
2475-1456
c
2022 IEEE. Personal use is permitted, but republication/redistribution requires IEEE permission.
See https://www.ieee.org/publications/rights/index.html for more information.
Authorized licensed use limited to: Stanford University. Downloaded on May 18,2022 at 02:45:54 UTC from IEEE Xplore. Restrictions apply.