Disciplined Geometric Programming¶
Disciplined geometric programming (DGP) is an analog of DCP for loglog convex functions, that is, functions of positive variables that are convex with respect to the geometric mean instead of the arithmetic mean.
While DCP is a ruleset for constructing convex programs, DGP is a ruleset for loglog convex programs (LLCPs), which are problems that are convex after the variables, objective functions, and constraint functions are replaced with their logs, an operation that we refer to as a loglog transformation. Every geometric program (GP) and generalized geometric program (GGP) is an LLCP, but there are LLCPs that are neither GPs nor GGPs.
CVXPY lets you form and solve DGP problems, just as it does for DCP problems. For example, the following code solves a simple geometric program,
import cvxpy as cp
# DGP requires Variables to be declared positive via `pos=True`.
x = cp.Variable(pos=True)
y = cp.Variable(pos=True)
z = cp.Variable(pos=True)
objective_fn = x * y * z
constraints = [
4 * x * y * z + 2 * x * z <= 10, x <= 2*y, y <= 2*x, z >= 1]
problem = cp.Problem(cp.Maximize(objective_fn), constraints)
problem.solve(gp=True)
print("Optimal value: ", problem.value)
print("x: ", x.value)
print("y: ", y.value)
print("z: ", z.value)
and it prints the below output.
Optimal value: 1.9999999938309496
x: 0.9999999989682057
y: 1.999999974180587
z: 1.0000000108569758
Note that to solve DGP problems, you must pass the option
gp=True
to the solve()
method.
This section explains what DGP is, and it shows how to construct and solve DGP problems using CVXPY. At the end of the section are tables listing all the atoms that can be used in DGP problems, similar to the tables presented in the section on DCP atoms.
For an indepth reference on DGP, see our accompanying paper. For interactive code examples, check out our notebooks.
Note: DGP is a recent addition to CVXPY. If you have feedback, please file an issue or make a pull request on Github.
Loglog curvature¶
Just as every Expression in CVXPY has a curvature (constant, affine, convex, concave, or unknown), every Expression also has a loglog curvature.
A function \(f : D \subseteq \mathbf{R}^n_{++} \to \mathbf{R}\) is said to be loglog convex if the function \(F(u) = \log f(e^u)\), with domain \(\{u \in \mathbf{R}^n : e^u \in D\}\), is convex (where \(\mathbf{R}^n_{++}\) denotes the set of positive reals and the logarithm and exponential are meant elementwise); the function \(F\) is called the loglog transformation of f. The function \(f\) is loglog concave if \(F\) is concave, and it is loglog affine if \(F\) is affine.
Every loglog affine function has the form
where \(x\) is in \(\mathbf{R}^n_{++}\), the \(a_i\) are real numbers, and \(c\) is a positive scalar. In the context of geometric programming, such a function is called a monomial function. A sum of monomials, known as a posynomial function in geometric programming, is a loglog convex function; A table of all the atoms with known loglog curvature is presented at the end of this page.
In the below table, \(F\) is the loglog transformation of \(f\), \(u=\log x\), and \(v=\log y\), where \(x\) and \(y\) are in the domain of \(f\)
LogLog Curvature 
Meaning 

loglog constant 
\(F\) is a constant (so f is a positive constant) 
loglog affine 
\(F(\theta u + (1\theta)v) = \theta F(u) + (1\theta)F(v), \; \forall u, \; v,\; \theta \in [0,1]\) 
loglog convex 
\(F(\theta u + (1\theta)v) \leq \theta F(u) + (1\theta)F(v), \; \forall u, \; v,\; \theta \in [0,1]\) 
loglog concave 
\(F(\theta u + (1\theta)v) \geq \theta F(u) + (1\theta)F(v), \; \forall u, \; v,\; \theta \in [0,1]\) 
unknown 
DGP analysis cannot determine the curvature 
CVXPY’s loglog curvature analysis can flag Expressions as unknown even when they are loglog convex or loglog concave. Note that any loglog constant expression is also loglog affine, and any loglog affine expression is loglog convex and loglog concave.
The loglog curvature of an Expression is stored in its
.log_log_curvature
attribute. For example, running the following
script
import cvxpy as cp
x = cp.Variable(pos=True)
y = cp.Variable(pos=True)
constant = cp.Constant(2.0)
monomial = constant * x * y
posynomial = monomial + (x ** 1.5) * (y ** 1)
reciprocal = posynomial ** 1
unknown = reciprocal + posynomial
print(constant.log_log_curvature)
print(monomial.log_log_curvature)
print(posynomial.log_log_curvature)
print(reciprocal.log_log_curvature)
print(unknown.log_log_curvature)
prints the following output.
LOGLOG CONSTANT
LOGLOG AFFINE
LOGLOG CONVEX
LOGLOG CONCAVE
UNKNOWN
You can also check the loglog curvature of an Expression by
calling the methods
is_log_log_constant()
, is_log_log_affine()
,
is_log_log_convex()
, is_log_log_concave()
. For example,
posynomial.is_log_log_convex()
would evaluate to True
.
Loglog curvature rules¶
For an Expression to have known loglog curvature, all of the Constants,
Variables, and Parameters it refers to must be elementwise positive. A
Constant is positive if its numerical value is positive. Variables
and Parameters are positive only if the keyword argument pos=True
is supplied to their constructors (e.g.,
x = cvxpy.Variable(shape=(), pos=True)
). To summarize,
when formulating a DGP problem, all Constants should be elementwise positive,
and all Variables and Parameters must be constructed with the attribute
pos=True
.
DGP analysis is exactly analogous to DCP analysis. It is based on a library of atoms (functions) with known monotonicity and loglog curvature and a a single composition rule. The library of atoms is presented at the end of this page; the composition rule is stated below.
A function \(f(expr_1, expr_2, ..., expr_n)\) is loglog convex if \(\text{ } f\) is a loglog convex function and for each \(expr_{i}\) one of the following conditions holds:
\(f\) is increasing in argument \(i\) and \(expr_{i}\) is loglog convex.
\(f\) is decreasing in argument \(i\) and \(expr_{i}\) is loglog concave.
\(expr_{i}\) is loglog affine.
A function \(f(expr_1, expr_2, ..., expr_n)\) is loglog concave if \(\text{ } f\) is a loglog concave function and for each \(expr_{i}\) one of the following conditions holds:
\(f\) is increasing in argument \(i\) and \(expr_{i}\) is loglog concave.
\(f\) is decreasing in argument \(i\) and \(expr_{i}\) is loglog convex.
\(expr_{i}\) is loglog affine.
A function \(f(expr_1, expr_2, ..., expr_n)\) is loglog affine if \(\text{ } f\) is an loglog affine function and each \(expr_{i}\) is loglog affine.
If none of the three rules apply, the expression \(f(expr_1, expr_2, ..., expr_n)\) is marked as having unknown curvature.
If an Expression satisfies the composition rule, we colloquially say that
the Expression “is DGP.” You can check whether an Expression is DGP
by calling the method is_dgp()
. For example, the assertions
in the following code block will pass.
import cvxpy as cp
x = cp.Variable(pos=True)
y = cp.Variable(pos=True)
monomial = 2.0 * constant * x * y
posynomial = monomial + (x ** 1.5) * (y ** 1)
assert monomial.is_dgp()
assert posynomial.is_dgp()
An Expression is DGP precisely when it has known loglog curvature, which means
at least one of the methods is_log_log_constant()
,
is_log_log_affine()
, is_log_log_convex()
,
is_log_log_concave()
will return True
.
DGP problems¶
A Problem
is constructed from an objective and
a list of constraints. If a problem follows the DGP rules, it is guaranteed to
be an LLCP and solvable by CVXPY. The DGP rules require that the problem
objective have one of two forms:
Minimize(loglog convex)
Maximize(loglog concave)
The only valid constraints under the DGP rules are
loglog affine == loglog affine
loglog convex <= loglog concave
loglog concave >= loglog convex
You can check that a problem, constraint, or objective satisfies the DGP
rules by calling object.is_dgp()
. Here are some examples of DGP and
nonDGP problems:
import cvxpy as cp
# DGP requires Variables to be declared positive via `pos=True`.
x = cp.Variable(pos=True)
y = cp.Variable(pos=True)
z = cp.Variable(pos=True)
objective_fn = x * y * z
constraints = [
4 * x * y * z + 2 * x * z <= 10, x <= 2*y, y <= 2*x, z >= 1]
assert objective_fn.is_log_log_concave()
assert all(constraint.is_dgp() for constraint in constraints)
problem = cp.Problem(cp.Maximize(objective_fn), constraints)
assert problem.is_dgp()
# All Variables must be declared as positive for an Expression to be DGP.
w = cp.Variable()
objective_fn = w * x * y
assert not objective_fn.is_dgp()
problem = cp.Problem(cp.Maximize(objective_fn), constraints)
assert not problem.is_dgp()
CVXPY will raise an exception if you call problem.solve(gp=True)
on a
nonDGP problem.
DGP atoms¶
This section of the tutorial describes the DGP atom library, that is, the atomic functions with known loglog curvature and monotonicity. CVXPY uses the function information in this section and the DGP rules to mark expressions with a loglog curvature. Note that every DGP expression is positive.
Infix operators¶
The infix operators +, *, /
are treated as atoms. The operators
*
and /
are loglog affine functions. The operator +
is loglog convex in both its arguments.
Note that in CVXPY, expr1 * expr2
denotes matrix multiplication
when expr1
and expr2
are matrices; if you’re running Python 3,
you can alternatively use the @
operator for matrix multiplication.
Regardless of your Python version, you can also use the matmul atom to multiply two matrices. To multiply two arrays or matrices
elementwise, use the multiply atom. Finally,
to take the product of the entries of an Expression, use
the prod atom.
Transpose¶
The transpose of any expression can be obtained using the syntax
expr.T
. Transpose is a loglog affine function.
Power¶
For any CVXPY expression expr
, the power operator expr**p
is equivalent
to the function power(expr, p)
. Taking powers is a loglog affine function.
Scalar functions¶
A scalar function takes one or more scalars, vectors, or matrices as arguments and returns a scalar. Note that several of these atoms may be applied along an axis; see the API reference or the DCP atoms tutorial for more information.
Function 
Meaning 
Domain 
Loglog curvature 
Monotonicity 

\(p \in \mathbf{R}^n_{+}\) \(p \neq 0\) 
\(x_1^{1/n} \cdots x_n^{1/n}\) \(\left(x_1^{p_1} \cdots x_n^{p_n}\right)^{\frac{1}{\mathbf{1}^T p}}\) 
\(x \in \mathbf{R}^n_{+}\) 

\(\frac{n}{\frac{1}{x_1} + \cdots + \frac{1}{x_n}}\) 
\(x \in \mathbf{R}^n_{+}\) 

\(\max_{ij}\left\{ X_{ij}\right\}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\min_{ij}\left\{ X_{ij}\right\}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

norm(x, 2) 
\(\sqrt{\sum_{i} \lvert x_{i} \rvert^2 }\) 
\(X \in\mathbf{R}^{n}_{++}\) 

\(\sqrt{\sum_{ij}X_{ij}^2 }\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\sum_{ij}\lvert X_{ij} \rvert\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\max_{ij} \{\lvert X_{ij} \rvert\}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(p \geq 1\) or 
\(\X\_p = \left(\sum_{ij} X_{ij}^p \right)^{1/p}\) 
\(X \in \mathbf{R}^{m \times n}_{++}\) 

\(0 < p < 1\) 
\(\X\_p = \left(\sum_{ij} X_{ij}^p \right)^{1/p}\) 
\(X \in \mathbf{R}^{m \times n}_{++}\) 

\(\prod_{ij}X_{ij}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(x^T P x\) 
\(x \in \mathbf{R}^n\), \(P \in \mathbf{R}^{n \times n}_{++}\) 

\(\left(\sum_{ij}X_{ij}^2\right)/y\) 
\(x \in \mathbf{R}^n_{++}\) \(y > 0\) 

\(\sum_{ij}X_{ij}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\sum_{ij}X_{ij}^2\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\mathrm{tr}\left(X \right)\) 
\(X \in\mathbf{R}^{n \times n}_{++}\) 

spectral radius of \(X\) 
\(X \in\mathbf{R}^{n \times n}_{++}\) 
Elementwise functions¶
These functions operate on each element of their arguments. For example, if
X
is a 5 by 4 matrix variable, then sqrt(X)
is a 5 by 4 matrix
expression. sqrt(X)[1, 2]
is equivalent to sqrt(X[1, 2])
.
Elementwise functions that take multiple arguments, such as maximum
and
multiply
, operate on the corresponding elements of each argument. For
example, if X
and Y
are both 3 by 3 matrix variables, then maximum(X,
Y)
is a 3 by 3 matrix expression. maximum(X, Y)[2, 0]
is equivalent to
maximum(X[2, 0], Y[2, 0])
. This means all arguments must have the same
dimensions or be scalars, which are promoted.
Function 
Meaning 
Domain 
Curvature 
Monotonicity 

diff_pos(x, y) 
\(x  y\) 
\(0 < y < x\) 

\(x \log (x)\) 
\(0 < x < 1\) 
None 

\(e^x\) 
\(x > 0\) 

\(\log(x)\) 
\(x > 1\) 

\(\max \left\{x, y\right\}\) 
\(x,y > 0\) 

\(\min \left\{x, y\right\}\) 
\(x, y > 0\) 

\(x*y\) 
\(x, y > 0\) 

\(1  x\) 
\(0 < x < 1\) 

\(1\) 
\(x > 0\) 
constant 
constant 

\(x\) 
\(x > 0\) 

\(\sqrt x\) 
\(x > 0\) 

\(x^2\) 
\(x > 0\) 

\(x e^x\) 
\(x > 0\) 
Vector/matrix functions¶
A vector/matrix function takes one or more scalars, vectors, or matrices as arguments and returns a vector or matrix.
Function 
Meaning 
Domain 
Curvature 
Monotonicity 

\(\left[\begin{matrix} X^{(1,1)} & \cdots & X^{(1,q)} \\ \vdots & & \vdots \\ X^{(p,1)} & \cdots & X^{(p,q)} \end{matrix}\right]\) 
\(X^{(i,j)} \in\mathbf{R}^{m_i \times n_j}_{++}\) 

\(\left[\begin{matrix}x_1 & & \\& \ddots & \\& & x_n\end{matrix}\right]\) 
\(x \in\mathbf{R}^{n}_{++}\) 

\(\left[\begin{matrix}X_{11} \\\vdots \\X_{nn}\end{matrix}\right]\) 
\(X \in\mathbf{R}^{n \times n}_{++}\) 

eye_minus_inv(X) 
\((I  X)^{1}\) 
\(X \in\mathbf{R}^{n \times n}_{++}, \lambda_{\text{pf}}(X) < 1\) 

\(A \in \mathbf{R}^{m \times n}\) 
\(\left[\begin{matrix}\prod_{j=1}^n x_j^{A_{1j}} \\\vdots \\\prod_{j=1}^n x_j^{A_{mj}}\end{matrix}\right]\) 
\(x \in \mathbf{R}^n_{++}\) 

\(\left[\begin{matrix}X^{(1)} \cdots X^{(k)}\end{matrix}\right]\) 
\(X^{(i)} \in\mathbf{R}^{m \times n_i}_{++}\) 

\(XY\) 
\(X \in\mathbf{R}^{m \times n}_{++}, Y \in\mathbf{R}^{n \times p}_{++}`\) 

\((sI  X)^{1}\) 
\(X \in\mathbf{R}^{n \times n}_{++}, \lambda_{\text{pf}}(X) < s\) 

\(X' \in\mathbf{R}^{m' \times n'}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) \(m'n' = mn\) 

\(x' \in\mathbf{R}^{mn}\) 
\(X \in\mathbf{R}^{m \times n}_{++}\) 

\(\left[\begin{matrix}X^{(1)} \\ \vdots \\X^{(k)}\end{matrix}\right]\) 
\(X^{(i)} \in\mathbf{R}^{m_i \times n}_{++}\) 