在cvxpy中表达式由变量、参数、数值常量(例如Python floats、Numpy matrices)、标准算数运算符(+, -, *, /) 和标准库函数。
如下是cvxpy表达式的例子:
from cvxpy import *
# Create variables and parameters.
//建立变量与参数
x, y = Variable(), Variable()
a, b = Parameter(), Parameter()
# Examples of CVXPY expressions.
//cvxpy表达式:
3.69 + b/3
x - 4*a
sqrt(x) - min_elemwise(y, x - a)
max_elemwise(2.66 - sqrt(y), square(x + 2*y))
表达式可以是标量、向量或者矩阵。表达式的维度被存储在expr.size,如果使用表达式的维度没有意义,cvxpy将会抛出异常,例如两个不同size的矩阵相加。
import numpy
X = Variable(5, 4)
A = numpy.ones((3, 5))
# Use expr.size to get the dimensions.
print "dimensions of X:", X.size
print "dimensions of sum_entries(X):", sum_entries(X).size
print "dimensions of A*X:", (A*X).size
# ValueError raised for invalid dimensions.
try:
A + X
except ValueError, e:
print e
dimensions of X: (5, 4)
dimensions of sum_entries(X): (1, 1)
dimensions of A*X: (3, 4)
Incompatible dimensions (3, 5) (5, 4)
CVXPY uses DCP analysis to determine the sign and curvature of each expression.
CVXPY使用DCP分析来求每个表达式的正负号与曲率
每一个表达式或者子表达式被标记为非负、非正、零或者未知。复合表达式的正负号可以从它的子表达式的正负号求出。
例如,expr1*expr2的正负号:
Unknown if either expression has unknown sign.
给一个表达式符号总是正确的,但是当一个表达式能通过更加复杂的分析标记符号时,DCP可能标记一个表达式为unknown。
例如x*x符号为正,但是x被标记为unknown。
cvxpy根据常量的值决定它的符号,对于标量常量,它的符号是容易求的。如果向量或者矩阵的每一项都是正(负),则向量或者矩阵常数被标记为正(负)。如果向量或矩阵的每一项有正有负,则向量或者矩阵被标记为unknown sign.
The sign of an expression is stored as expr.sign:
x = Variable()
a = Parameter(sign="negative")
c = numpy.array([1, -1])
print "sign of x:", x.sign
print "sign of a:", a.sign
print "sign of square(x):", square(x).sign
print "sign of c*a:", (c*a).sign
sign of x: UNKNOWN
sign of a: NEGATIVE
sign of square(x): POSITIVE
sign of c*a: UNKNOWN
每个表达式或子表达式被标记为下列曲率(根据它们的变量):
使用如下的曲率规则。正如符号分析,结论总是正确的。但是当一个表达式是凸的或者凹的时,一个简单的分析能标记表达式是unknown。注意常量标记为affine,任何仿函数能标记为凸的或者凹的。
一个问题能够由目标函数和一系列约束构造。如果问题遵从DCP规则,这个问题将是凸的,能够被cvxpy解决。DCP规则要求目标函数有以下两种形式:
//Here are some examples of DCP and non-DCP problems:
x = Variable()
y = Variable()
# DCP problems.
prob1 = Problem(Minimize(square(x - y)), [x + y >= 0])
prob2 = Problem(Maximize(sqrt(x - y)),
[2*x - 3 == y,
square(x) <= 2])
print "prob1 is DCP:", prob1.is_dcp()
print "prob2 is DCP:", prob2.is_dcp()
# Non-DCP problems.
# A non-DCP objective.
prob3 = Problem(Maximize(square(x)))
print "prob3 is DCP:", prob3.is_dcp()
print "Maximize(square(x)) is DCP:", Maximize(square(x)).is_dcp()
# A non-DCP constraint.
prob4 = Problem(Minimize(square(x)), [sqrt(x) <= 2])
print "prob4 is DCP:", prob4.is_dcp()
print "sqrt(x) <= 2 is DCP:", (sqrt(x) <= 2).is_dcp()
prob1 is DCP: True
prob2 is DCP: True
prob3 is DCP: False
Maximize(square(x)) is DCP: False
prob4 is DCP: False
sqrt(x) <= 2 is DCP: False
CVXPY will raise an exception if you call problem.solve() on a non-DCP problem.
# A non-DCP problem.
prob = Problem(Minimize(sqrt(x)))
try:
prob.solve()
except Exception as e:
print e
Problem does not follow DCP rules.