*Disciplined convex programming* (DCP) requires all models obey a set of
rules, or conventions, that govern how expressions and functions can appear
in objectives and constraints. These rules, which we call the *DCP ruleset*,
are drawn from basic principles of convex analysis and are relatively easy
to learn. But they are not exhaustive, which means that it is possible to
construct expressions and models that are known to be convex, but still
violate the rules.

To illustrate the difference between *convexity* and *disciplined convexity*,
consider the function \(f(x)=\sqrt{x^2+1}\). It is simple to prove that
this function is convex; its second derivative
\(f^{(2)}(x)=(x^2+1)^{-3/2}\) is positive for all \(x\). The ruleset
is silent on derivatives, however. And if you attempt to express \(f\)
in the obvious manner in CVX, you will see this error:

```
>> sqrt(x^2+1)
Error using cvx/sqrt (line 61)
Disciplined convex programming error:
Illegal operation: sqrt( {nonnegative convex} ).
```

The problem is that the *composition rules* forbid the
application of a concave function (like `sqrt`) to a convex expression
(like `x^2+1`), since that *usually* produces a nonconvex result. So CVX
rejects the expression on this basis.

Fortunately, most situations like this can be resolved simply by rewriting the expression. In this case, \(f\) can also be written as \(f(x)=\|[x~1]\|_2\); a form which CVX accepts:

```
>> norm([x 1])
ans =
cvx nonnegative convex expression (scalar)
```

This expression is acceptable because `norm` is among the
*functions supported by CVX*, and it is being used in a
manner compliant with the *composition rules*. So
\(f(x)=\sqrt{x^2+1}\) can indeed be used in CVX models, as long as it is
expressed in a compliant manner.

At first, the DCP ruleset may seem arbitrary or restrictive, but it serves a
very important purpose. Each rule corresponds to a specific step that CVX
takes to convert models to solvable form. When CVX rejects a model for a rule
violation, then, it is doing so *because it does not know how to solve it*.
Put another way, by complying with the rules, you are not only proving
that your model is convex, you are also giving CVX *a detailed recipe for
solving it.* (We thank you for the help!)

In truth, it is never the *rules* that ultimately prevent a model from being
represented in CVX. Rather, it is the finite size of the function library,
which is in turn limited by the capabilities of the underlying numerical
solvers. Still, the greater your mastery of the DCP ruleset, the more
productive you will be.

Acceptable objective expressions come in one of two forms:

- Convex minimization:
`minimize(`*expr*`)`, where*expr*is convex (or real affine). - Concave maximization:
`maximize(`*expr*`)`, where*expr*is concave (or real affine).

A model does not need to have an objective; such a problem is called a
*feasibility problem*. CVX will attempt to find a single point that satisfies
all of the constraints.

Acceptable constraints come in one of four forms:

- A
*less-than inequality constraint*, using`<=`, where the left side is convex and the right side is concave. - A
*greater-than inequality constraint*, using`>=`, where the left side is concave and the right side is convex. - An
*equality constraint*, using`==`, where both the left and right-hand sides are affine. - A
*set membership constraint*, using`<In>`, involving affine expressions. (See*Set membership*for more details.)

*Non*-equality constraints, constructed using `~=`, are *never allowed*.
(Such constraints are not convex.)

CVX treats strict `<` `>` inequalities identically to non-strict `<=`
`>=` inequalities, so to avoid confusion the use of strict inequalities is
*strongly discouraged*. For more information, see *Strict inequalities* below.

Inequality constraints must be real. Equality constraints, on the other hand, may be complex. Complex equality constraints are equivalent to two real equality constraints, one for the real part and one for the imaginary part. An equality constraint with a real side and a complex side, then, has the effect of constraining the imaginary part of the complex side to be zero.

Each scalar expression and subexpression is analyzed to determin
its *curvature* and *sign*. Vectors, matrices, and arrays are analyzed on an
elementwise basis.

CVX considers four types of *curvature*: curvature: *constant*, *affine*,
*convex*, and *concave*. The reader should already be familiar with these
definitions. But for review, a function
\(f:\mathbf{R}^n\rightarrow\mathbf{R}\) defined on all
\(\mathbf{R}^n\), the categories have the following meanings:

\[\begin{split}\begin{array}{l@{\quad}ll}
\text{constant} & f(\alpha x + (1-\alpha)y) = f(x)
& \forall x,y\in\mathbf{R}^n,~\alpha\in\mathbf{R} \\
\text{affine} & f(\alpha x + (1-\alpha)y) = \alpha f(x) + (1-\alpha) f(y)
& \forall x,y\in\mathbf{R}^n,~\alpha\in\mathbf{R} \\
\text{convex} & f(\alpha x + (1-\alpha)y) \leq \alpha f(x) + (1-\alpha) f(y)
& \forall x,y\in\mathbf{R}^n,~\alpha\in[0,1] \\
\text{concave} & f(\alpha x + (1-\alpha)y) \geq \alpha f(x) + (1-\alpha) f(y)
& \forall x,y\in\mathbf{R}^n,~\alpha\in[0,1]
\end{array}\end{split}\]

There is, of course, significant overlap in these categories: constant expressions are also affine, and (real) affine expressions are both convex and concave. Convex and concave expressions are real by definition, but constants and affine expressions can be complex.

CVX does *not* determine convexity using the above definitions. Instead,
curvature is determined recursively applying the following rules. While this
list may seem long, it is for the most part an enumeration of basic rules of
convex analysis for combining convex, concave, and affine forms: sums,
multiplication by scalars, and so forth.

- A valid constant expression is
- any well-formed expression that immediately evaluates to a finite value.

- A valid affine expression is
- a valid constant expression;
- a declared variable;
- the sum or difference of affine expressions;
- the product of an affine expression and a constant.
- a valid affine function expression—see
*Composition rules*;

- A valid convex expression is
- a valid constant or affine expression;
- the sum of two or more convex expressions;
- the difference between a convex expression and a concave expression;
- the product of a convex expression and a nonnegative constant;
- the product of a concave expression and a nonpositive constant;
- the negation of a concave expression;
- a valid convex function expression—see
*Composition rules*; - an affine scalar raised to a constant power \(p\geq 1\), \(p\neq3,5,7,9,...\);
- a convex scalar quadratic form—see
*Scalar quadratic forms*.

- A valid concave expression is
- a valid constant or affine expression;
- the sum of two or more concave expressions;
- the difference between a concave expression and a convex expression;
- the product of a concave expression and a nonnegative constant;
- the product of a convex expression and a nonpositive constant;
- the negation of a convex expression;
- a valid concave function expression—see
*Composition rules*; - a concave scalar raised to a power \(p\in(0,1)\);
- a concave scalar quadratic form—see
*Scalar quadratic forms*.

We note that the set of rules listed above is redundant; there are much smaller, equivalent sets of rules. For matrix and array expressions, these rules are applied on an elementwise basis.

Of particular note is that these expression rules generally forbid *products*
between nonconstant expressions, with the exception of scalar quadratic forms.
For example, the expression `x*sqrt(x)` happens to be a convex function of
`x`, but its convexity cannot be verified using the CVX ruleset, and so is
rejected. (It can be expressed as `pow_p(x,3/2)`, however.) We call this
the *no-product rule*:

- The product or ratio of two non-constant (affine, convex, concave) expressions is forbidden.

Adherence to the no-product rule will go a long way to insuring that you
construct valid expressions. There is one notable exception to this rule,
however: see *Scalar quadratic forms* below. But quadratic forms are, strictly
speaking, an unnecessary convenience, since CVX includes a `quad_form`
function that provides the same functionality.

CVX also keeps track of the *sign* of an expression as well. Expressions are
classified as *positive*, *negative*, and *unknown sign*. In a slight abuse of
notation, nonnegative expressions are also treated as positive, and
nonpositive expressions are also treated as negative. It should be noted that
CVX does *not* perform any sort of advanced interval analysis to determine if
an expression is positive or negative. As with curvature, it draws its
conclusions by applying a simple set of rules:

- A “positive” expression is
- a positive constant (or zero);
- a variable
*declared*nonnegative (see*Variables*); - a diagonal element of a variable declared semidefinite
(see
*Variables*); - a call to any function specifically labeled as
*positive*(see*Functions*below); - a negative expression multiplied by a negative constant;
- a positive expression multiplied by a positive constant;
- the sum of positive expressions.

- A “negative” expression is
- a negative constant (or zero);
- a call to any function specifically labeled as
*negative*(see*Functions*below); - a negative expression multiplied by a positive constant;
- a positive expression multiplied by a negative constant;
- the sum of negative expressions.

That’s it! Any expression whose sign cannot be determined from these rules is
classified as having *unknown sign*. For example, the expression `x - 1` has
unknown sign—even if a constraint in the model ensures that `x >= 1`.
These rules provide just enough information to CVX to give the user more
flexibility in how it combines functions together; more on this in
*Sign-dependent monotonicity* below.

Now let us consider how CVX classifies an expression of the form \(f(\arg_1,\arg_2,\dots,\arg_n)\), where \(f\) is a function from CVX’s function library, and each argument \(arg_k\) is an otherwise well- posed scalar CVX expression. In the case where a MATLAB function accepts vector, matrix, or array arguments, everything we discuss here is applied in an elementwise fashion. For instance, the expression norm(x), where x is a vector of length \(n\), can be thought of as a function expression involving \(n\) separate scalar arguments.

In order to proceed, we must first understand the properties of the function
\(f\) itself. As with basic expressions, CVX categorizes functions
according to their *curvature* and *sign*. They also obtain two more
attributes as well: *monotonicity* and *domain*. For functions with only one
argument, the categorization is straightforward. Some examples are given in
the table below.

The *domain* of a function is simply the set of points over which a function
is well-defined. For a convex or concave function, this set is always convex.
The domain serves as an *implicit constraint* on the function’s input. For
instance, if we form `sqrt(x+1)` in a CVX specification, a new constraint
`x+1>=0` is automatically assumed. There is no need to add such a constraint
separately. Monotonicity is also considered with respect to the function’s
domain; so, for instance, `sqrt(x)` is considered increasing, since that is
indeed the case for all nonnegative inputs.

CVX does *not* consider a function to be convex or concave if it is so only
over a portion of its domain, even if the argument is constrained to lie in
one of these portions. For example, consider the function \(1/x\). This
function is convex for \(x>0\), and concave for \(x<0\). But you can
never write `1/x` in CVX (unless `x` is constant), even if you have
imposed a constraint such as `x>=1`, which restricts `x` to lie in the
convex portion of function. You *can*, however, use the CVX function
`inv_pos(x)`, listed above, which is defined to have the domain
:math:mathbb{R}_{++}. CVX recognizes this function as convex and
decreasing.

CVX considers two types of monotonicity: *increasing* and *decreasing*. In a
slight abuse of notation, we classify nondecreasing functions as increasing,
and nonincreasing functions as decreasing. These categories have the following
meanings:

\[\begin{split}\begin{array}{l@{\quad}l}
\text{increasing} & x \geq y ~~\Longrightarrow~~ f(x) \geq f(y) \\
\text{decreasing} & x \geq y ~~\Longrightarrow~~ f(x) \leq f(y)
\end{array}\end{split}\]

A function that is neither increasing or decreasing is called *nonmonotonic*.
In more recent versiojns of CVX, we also consider *sign-dependent*
monotonicity. For example, the functions `square(x)` and `abs(x)`
are decreasing for negative \(x\) and increasing for positive \(x\).
Previous versions of CVX classifed these functions as nonmonotonic, which
affected their use in compositions; more on this in
*Sign-dependent monotonicity* below.

For functions with multiple arguments, curvature is always considered
*jointly*, but monotonicity can be considered on an *argument-by-argument*
basis. For example, the function `quad_over_lin(x,y)`

\[\begin{split}f_{\text{quad\_over\_lin}}(x,y) = \begin{cases} |x|^2/y & y > 0 \\
+\infty & y\leq 0 \end{cases}\end{split}\]

is jointly convex in both \(x\) and \(y\) and decreasing in \(y\), and exhibits sign-dependent monotonicity in x.

Some functions are convex, concave, or affine only for a *subset* of its
arguments. For example, the function `norm(x,p)` where `p \geq 1` is
convex only in its first argument. Whenever this function is used in a CVX
specification, then, the remaining arguments must be constant, or CVX will
issue an error message. Such arguments correspond to a function’s parameters
in mathematical terminology; *e.g.*,

\[f_p(x):\mathbf{R}^n\rightarrow\mathbf{R}, \quad f_p(x) \triangleq \|x\|_p\]

So it seems fitting that we should refer to such arguments as *parameters* in
this context as well. Henceforth, whenever we speak of a CVX function as being
convex, concave, or affine, we will assume that its parameters are known and
have been given appropriate, constant values.

Armed with relevant information about \(f\) and the classification of the
arguments \(\arg_k\) according to the rules in *Expression rules*, we may
proceed to classify the full expression. We call the rules that govern these function expressions the *composition rules*.

Perhaps the most basic composition rule in convex anaysis is that convexity
is closed under composition with an affine mapping. For example, function
`square(x)`—which, as its name implies, computes \(f(x)=x^2\)—is
convex for real arguments x. So if `x` is a real variable of dimension
\(n\), `a` is a constant \(n\)-vector, and `b` is a constant, the
expression

```
square( a' * x + b )
```

is accepted by CVX, which knows that it is convex.

The affine composition rule is just one one case in a more sophisiticated composition ruleset. Here is the complete set:

- The function expression \(f(\arg_1,\arg_2,\dots,\arg_n)\) is affine if \(f\) is affine and every expression \(\arg_k\) is affine.
- The function expression \(f(\arg_1,\arg_2,\dots,\arg_n)\) is convex
if \(f\) is convex (or affine), and if one of the following is true
for
*every*expression \(\arg_k\):- \(\arg_k\) is affine.
- \(\arg_k\) is convex,
*and*the function is increasing in argument \(k\). - \(\arg_k\) is concave,
*and*the function is decreasing in argument \(k\).

- The function expression \(f(\arg_1,\arg_2,\dots,\arg_n)\) is concave
if \(f\) is concave (or affine), and if one of the following is true
for
*every*expression \(\arg_k\):- \(\arg_k\) is affine.
- \(\arg_k\) is concave,
*and*the function is increasing in argument \(k\). - \(\arg_k\) is convex,
*and*the function is decreasing in argument \(k\).

For more background on these composition rules, see Convex Optimization, Section 3.2.4.

Let us examine some examples. The maximum function is convex and increasing
in every argument, so it can accept any convex expressions as arguments. For
example, if `x` is a vector variable, then

```
max( abs( x ) )
```

obeys the “convex/increasing/convex” composition rule, and is therefore accepted by CVX, and classified as convex. As another example, consider the sum function, which is both convex and concave (since it is affine), and increasing in each argument. Therefore the expressions

```
sum( square( x ) )
sum( sqrt( x ) )
```

are recognized as valid in CVX, and classified as convex and concave, respectively. The first one follows from the “convex/increasing/convex” rule, while the second follows from the “concave/increasing/concave” rule.

Most people who know basic convex analysis like to think of these simpler
examples in terms of more specific rules: a maximum of convex functions is
convex, and a sum of convex (concave) functions is convex (concave). But as
you can see, these rules are just *special cases* of the this general
composition ruleset. In fact, with the exception of scalar quadratic
expressions, the entire DCP ruleset can be thought of as special cases
of these rules.

For a more complex example, suppose `x` is a vector variable, and `A`,
`b`, and `f` are constants with appropriate dimensions. CVX recognizes
the expression

```
sqrt(f'*x) + min(4,1.3-norm(A*x-b))
```

as concave. Consider the term `sqrt(f'*x)`. CVX recognizes that `sqrt` is
concave and `f'*x` is affine, so it concludes that `sqrt(f'*x)` is
concave. Now consider the second term `min(4,1.3-norm(A*x-b))`. CVX
recognizes that `min` is concave and increasing, so it can accept concave
arguments. CVX recognizes that `1.3-norm(A*x-b)` is concave, since it is the
difference of a constant and a convex function. So CVX concludes that the
second term is also concave. The whole expression is then recognized as
concave, since it is the sum of two concave functions.

For a negative example, we can return to the original expression presented in
the beginnnig of this chapter, `sqrt( x^2 + 1 )`. Assuming that `x` is a
scalar variable, this is the composition of a concave, increasing function
`sqrt` and a convex expression `x^2+1`. According to the composition
rules, `sqrt` can accept a *concave* argument, not a convex argument, so CVX
rejects it. On the other hand, `norm([x 1])` is the composition of a convex
function `norm` and an affine expression `[x 1]`, so CVX can indeed accept
that.

Monotonicity is clearly a critical aspect of the rules for nonlinear compositions. Previous versions of CVX enforced these rules in a way that occasionally produced some unfortunate consequences. For example, consider the expression

```
square( square( x ) + 1 )
```

where `x` is a scalar variable. This expression is in fact convex, since
\((x^2+1)^2 = x^4+2x^2+1\) is convex. However, previous versions of CVX
used to *reject* this expression, because `square` is nonmontonic; and so
it may not accept a convex argument according to the strictest reading of the
composition rules above. Indeed, the square of a convex function is not, in
general, convex: for example, \((x^2-1)^2 = x^4-2x^2+1\) is not convex.

In practice, this explanation may proved unsatisfying. After all, even though
`square` is nonmonotonic over the entire real line, the expression
`square(x)+1` has a range of \([1,+\infty)\). And *over that interval*,
`square` is increasing. Therefore, one could justifiably claim that the
composition rules are satisfied it this case.

The latest versions of CVX implement a simple but effective approach for
extending the composition rules to cover such cases: *sign-dependent
monotonicity*. To accomplish this, functions that are positive or negative
over their entire domain are noted as such, so this information can be used
in the sign analysis described in *Sign* above. Furthermore, each
functions monotonicity is considered *with respect to the sign of its
input*. So, for example, `square` is increasing for positive inputs, and
decreasing for negative inputs.

Under this new regime, we can now see how `square(square(x)+1)` can be
accepted by CVX. First, CVX knows that `square` is nonnegative; and as the
sum of two nonnegative terms, it draws the same conclusion about
`square(x)+1`. Because of this, CVX can conclude that the outer instance to
`square` is increasing. CVX determines that this expression is the
composition of a convex, increasing function and a convex argument, and it is
accepted by the ruleset.

Clearly, sign-dependent monotonicity, and the simple rule-based sign analysis performed in CVX, is limited. For example, entr( x ) defined above is increasing for \(x\geq 1/e\) and decreasing for \(x\leq 1/e\), but CVX does not consider that. But our experience with implementations found in CVXPY, the Stanford DCP expression analyzer, and our internal version of CVX suggest that this covers nearly all of the cases CVX users are likely to encounter.

In its pure form, the DCP ruleset forbids even the use of simple quadratic
expressions such as `x * x` (assuming `x` is a scalar variable). For
practical reasons, we have chosen to make an exception to the ruleset to
allow for the recognition of certain specific quadratic forms that map
directly to certain convex quadratic functions (or their concave negatives)
in the CVX atom library:

x .* x |
square( x ) (real x) |

conj( x ) .* x |
square_abs( x ) |

y' * y |
sum_square_abs( y ) |

(A*x-b)'*Q*(Ax-b) |
quad_form( A*x - b, Q ) |

CVX detects the quadratic expressions such as those on the left above, and determines whether or not they are convex or concave; and if so, translates them to an equivalent function call, such as those on the right above.

CVX examines each *single* product of affine expressions, and each *single*
squaring of an affine expression, checking for convexity; it will not check,
for example, sums of products of affine expressions. For example, given
scalar variables `x` and `y`, the expression

```
x ^ 2 + 2 * x * y + y ^2
```

will cause an error in CVX, because the second of the three terms
`2 * x * y`, is neither convex nor concave. But the equivalent
expressions

```
( x + y ) ^ 2
( x + y ) * ( x + y )
```

will be accepted.

CVX actually completes the square when it comes across a scalar quadratic
form, so the form need not be symmetric. For example, if `z` is a vector
variable, `a`, `b` are constants, and `Q` is positive definite, then

```
( z + a )' * Q * ( z + b )
```

will be recognized as convex. Once a quadratic form has been verified by
CVX, it can be freely used in any way that a normal convex or concave
expression can be, as described in *Expression rules*.

Quadratic forms should actually be used *less frequently* in disciplined
convex programming than in a more traditional mathematical programming
framework, where a quadratic form is often a smooth substitute for a
nonsmooth form that one truly wishes to use. In CVX, such
substitutions are rarely necessary, because of its support for nonsmooth
functions. For example, the constraint

```
sum( ( A * x - b ) .^ 2 ) <= 1
```

is equivalently represented using the Euclidean norm:

```
norm( A * x - b ) <= 1
```

With modern solvers, the second form is more naturally represented using a second-order cone constraint—so the second form may actually be more efficient. In fact, in our experience, the non-squared form will often be handled more accurately. So we strongly encourage you to re-evaluate the use of quadratic forms in your models, in light of the new capabilities afforded by disciplined convex programming.

As mentioned in *Constraints*, strict inequalities `<`, `>` are
interpreted in an identical fashion to nonstrict inequalities `>=`,
`<=`. It is important to note that CVX cannot guarantee that an inequality
will be strictly satisfied at the solution it computes. This is not simply a
choice we have made in CVX; it is a natural consequence of both the
underlying mathematics and the design of convex optimization solvers. For
that reason, we *strongly* discourage the use of strict inequalities in CVX,
and a future version may remove them altogether.

When a strict inequality is essential to your model, you may need to take
additional steps to ensure compliance. In some cases, this can be
accomplished through *normalization*. For instance, consider a set of
homogeneous equations and inequalities:

\[A x = 0, \quad C x \preceq 0, \quad x \succ 0\]

Except for the strict inequality, \(x=0\) would be an acceptable solution; indeed the need to avoid the origin is the very reason for the strict inequality. However, note that if a given \(x\) satisfies these constraints, then so does \(\alpha x\) for all \(\alpha>0\). By eliminating this degree of freedom with normalization, we can eliminate the strict inequality; for instance:

\[A x = 0, \quad C x \preceq 0, \quad x \succ 0, \quad \mathbf{1}^T x = 1\]

If normalization is not a valid approach for your model, you may simply need
to convert the strict inequality into a non-strict one by adding a small
offset; *e.g.*, convert `x > 0` to, say, `x >= 1e-4`. Note that the
bound needs to be large enough so that the underlying solver considers it
numerically significant.

Finally, note that for some functions like `log(x)` and `inv_pos(x)`,
which have domains defined by strict inequalities, the domain restriction is
handled *by the function itself*. You do not need to add an explicit
constraint `x > 0` to your model to guarantee that the solution is
positive.

Given our strong emphasis on adherence to the DCP ruleset, experienced users
of CVX may be surprised to accidentally stumble upon certain expressions
involving `log` and `exp` that violate the ruleset *but are accepted
anyway*; for example, `log(exp(x)+1)`. It turns out that this is an
artifact of CVX’s support for *geometric programming*; and
since it also requires the use of CVX’s experimental *successive
approximation approach*, it is unsupported. Nevertheless,
advanced users may be interested in reading more about these “hidden” rules
in the *Advanced topics* chapter.