Reference
Table of Contents
- Operations for declaring and sizing variables
- Operations on expressions
- Operations for declaring constraints
- Operations for optimization
- Operations for creating custom functions
- Operations for analyzing DCP structure
Operations for declaring and sizing variables
Variables are created with one of the following idioms:
//instantiate a scalar variable
val x = variable()
val x = variable(scalar())
//instantiate a vector variable of the given length
val x = variable(vector(length))
//instantiates a symmetric matrix variable of the given size
val x = variable(smatrix(size))
//instantiates a variable with the same shape as variable y
val x = variable(shapeof(y))
Note the use of the val
keyword instead of the var
keyword, and
the lack of a type annotation.
Using var
may result in unexpected behavior.
Here, length
and size
must both be integer-valued (although they
need not be compile-time constants), while y
must be the name of an already-declared
variable.
All variables are also OptiCVX expressions, and are assigned a vexity of "affine".
Operations on expressions
In addition to variable expressions as described above, expressions can also be created from
scalar constants. To use a double-typed scalar as an expression in OptiCVX code, simply include
it in the code where you want the expression to be used. If the scalar is a compile-time
constant, then its sign will be determined and used for DCP validation. If the value is known
only at runtime, this can't be done, so it needs to be annotated with its sign using either the
positive
or negative
function, as illustrated below:
//if f is some double-typed variable:
positive(f)*max(x,y) //result is still convex
negative(f)*max(x,y) //result is now concave
The positive
and negative
functions check the sign of their arguments
at runtime and will emit a warning if the sign is not what was expected, since this indicates
a runtime DCP error.
Expressions can be combined into new expressions using any of the following mathematical operators:
//sum or difference of two expressions A and B
A + B
A - B
//negation of an expression A
-A
//product of an expression A with a scalar constant c
c * A
A * c
//indexing of a vector at index i or a matrix at index (i,j)
A(i)
A(i,j)
These operations assign vexity as specified in the DCP rules. In particular, for an expression to be indexed it must be affine, and the result of the indexing will be a scalar affine expression.
Operations for declaring constraints
OptiCVX supports constraints created by the following functions and operators:
//affine constraints
constrain_zero(A)
A == B
//inequality constraints (linear programming)
constrain_nonnegative(A)
A <= B
A >= B
//second-order cone constraint: norm(A: vector) <= B: scalar
constrain_secondordercone(A,B)
//semidefinitness constraint (for smatrix-shaped A)
constrain_semidefinite(A)
Affine and conic constraints require their arguments to be affine. Inequality constraints require their arguments to have appropriate vexity to satisfy the DCP requirements.
Operations for optimization
OptiCVX supports the following optimization expressions:
//minimization and maximization of expression E over variables Vi
minimize(E) over (V1,V2,...,Vn)
maximize(E) over (V1,V2,...,Vn)
//recover the value of a (scalar-shaped) expression X after the solver has run
resolve(X)
Minimization expressions require convex arguments and maximization expressions require concave arguments. It is an error to try to resolve an expression when some of its dependant variables have not yet been bound to a solver.
Operations for creating custom functions
OptiCVX supports the creation of arbitrary convex functions by the user, provided those functions can be expressed as partial optimization functions over the provided conic primitives (positive simplex, second-order cone, and semidefinite-cone). The syntax for doing so is illustrated below:
//create a custom function foo with n arguments
val foo = cvxfun (v) arguments (m1,m2,...,mn) body ((x1,x2,...,xn) => {
...
body of function
...
})
//where v represents the vexity of the function, and can take on the values
affine
convex
concave
novexity
//and mi represents the monotonicity of the i-th argument, and can take on the values
constant
nondecreasing
nonincreasing
nomonotonicity
The body of the function must be a function of the arguments xi
, and should typically be
a partial optimization operation. See the example code for an example of this.
Once we have defined the function, we can invoke it as follows:
//invoke function foo just as we would a normal function
foo(x1,x2,...,xn)
The result is an OptiCVX expression with vexity as defined in the DCP ruleset.
Operations for analyzing DCP structure
OptiCVX contains one operator that allows the user to analyze the structure of the convex
program that he/she is writing. The introspect
operator will print a diagnostic
message at staging-time that specifies the vexity of the expression. It is used as follows:
//print a diagnostic message about the vexity of expression A
introspect(A)
introspect(A,"name")
The second form here will tag the printed vexity expression with the given name, which must be a string constant.