首页 » 技术分享 » Python.CVXPY学习指南一

Python.CVXPY学习指南一

 

前言

cvxpy是解决凸优化问题的,在使用之前要确保目标函数是一个凸优化问题(包括其中的变量范围设置,参数设置等)

CVXPY是什么?

CVXPY是一种可以内置于Python中的模型编程语言,解决凸优化问题。它可以自动转化问题为标准形式,调用解法器,解包结果集

如下代码是使用CVXPY解决一个简单的优化问题:

from cvxpy import *
# Create two scalar optimization variables.
# 在CVXPY中变量有标量(只有数值大小),向量,矩阵。
# 在CVXPY中有常量(见下文的Parameter)
x = Variable() //定义变量x,定义变量y。两个都是标量
y = Variable()
# Create two constraints.
//定义两个约束式
constraints = [x + y == 1,
              x - y >= 1]
//优化的目标函数
obj = Minimize(square(x - y))
//把目标函数与约束传进Problem函数中
prob = Problem(obj, constraints)
prob.solve()  # Returns the optimal value.
print "status:", prob.status
print "optimal value", prob.value //最优值
print "optimal var", x.value, y.value //x与y的解
status: optimal
optimal value 0.999999999761
optimal var 1.00000000001 -1.19961841702e-11
//状态域被赋予'optimal',说明这个问题被成功解决。
//最优值是针对所有满足约束条件的变量x,y中目标函数的最小值
//prob.solve()返回最优值,同时更新prob.status,prob.value,和所有变量的值。

改变已经创建的问题

Problems是不可改变的,意味着在问题被创建之后它不可被改变。为了改变已有问题的目标或者约束,应该创建一个新的问题

# Replace the objective.//不同的目标函数,相同的约束
prob2 = cvx.Problem(cvx.Maximize(x + y), prob.constraints)
print("optimal value", prob2.solve())

# Replace the constraint (x + y == 1).//不同的约束,相同的目标函数
constraints = [x + y <= 3] + prob.constraints[1:] //注意:此处是列表相加,prob.constraints[1:]取prob的约束集中
//从第二个开始的所有约束。
prob2 = cvx.Problem(prob.objective, constraints)
print("optimal value", prob2.solve())
optimal value 1.0
optimal value 3.00000000006

不可行问题与无边界问题

如果一个问题是不可行问题,这个prob.status将会被设置为’infeasible’,如果问题是无边界的,prob.status=unbounded,变量的值域将不会被更新。

import cvxpy as cvx
x = cvx.Variable()
//一个不可行问题
# An infeasible problem.
prob = cvx.Problem(cvx.Minimize(x), [x >= 1, x <= 0])
prob.solve()
print("status:", prob.status)
print("optimal value", prob.value)
// 无边界问题
# An unbounded problem.
prob = cvx.Problem(cvx.Minimize(x))
prob.solve()
print("status:", prob.status)
print("optimal value", prob.value)
status: infeasible
optimal value inf
status: unbounded
optimal value -inf

CVXPY的问题状态即prob.status

cvxpy的prob.status可以有如下状态值:
OPTIMAL: 问题被成功解决
INFEASIBLE:问题无解
UNBOUNDED:无边界
OPTIMAL_INACCURATE:解不精确
INFEASIBLE_INACCURATE:
UNBOUNDED_INACCURATE:
If the solver completely fails to solve the problem, CVXPY throws a SolverError exception. If this happens you should try using other solvers. See the discussion of Choosing a solver for details.如果CVXPY求解器求解完全失败,CVXPY将会抛出一个SolverError异常,如果这发生,你应该使用其他求解器cvxpy求解器

# Solving a problem with different solvers.
x = cvx.Variable(2)
obj = cvx.Minimize(x[0] + cvx.norm(x, 1))
constraints = [x >= 2]
prob = cvx.Problem(obj, constraints)

# Solve with ECOS.
prob.solve(solver=cvx.ECOS)
print("optimal value with ECOS:", prob.value)

# Solve with ECOS_BB.
prob.solve(solver=cvx.ECOS_BB)
print("optimal value with ECOS_BB:", prob.value)

# Solve with CVXOPT.
prob.solve(solver=cvx.CVXOPT)
print("optimal value with CVXOPT:", prob.value)

# Solve with SCS.
prob.solve(solver=cvx.SCS)
print("optimal value with SCS:", prob.value)

# Solve with GLPK.
prob.solve(solver=cvx.GLPK)
print("optimal value with GLPK:", prob.value)

# Solve with GLPK_MI.
prob.solve(solver=cvx.GLPK_MI)
print("optimal value with GLPK_MI:", prob.value)

# Solve with GUROBI.
prob.solve(solver=cvx.GUROBI)
print("optimal value with GUROBI:", prob.value)

# Solve with MOSEK.
prob.solve(solver=cvx.MOSEK)
print("optimal value with MOSEK:", prob.value)

# Solve with Elemental.
prob.solve(solver=cvx.ELEMENTAL)
print("optimal value with Elemental:", prob.value)

# Solve with CBC.
prob.solve(solver=cvx.CBC)
print("optimal value with CBC:", prob.value)
optimal value with ECOS: 5.99999999551
optimal value with ECOS_BB: 5.99999999551
optimal value with CVXOPT: 6.00000000512
optimal value with SCS: 6.00046055789
optimal value with GLPK: 6.0
optimal value with GLPK_MI: 6.0
optimal value with GUROBI: 6.0
optimal value with MOSEK: 6.0
optimal value with Elemental: 6.0000044085242727
optimal value with CBC: 6.0
//Use the installed_solvers utility function to get a list of the solvers your installation of CVXPY //supports.

print installed_solvers()
['CBC', 'CVXOPT', 'MOSEK', 'GLPK', 'GLPK_MI', 'ECOS_BB', 'ECOS', 'SCS'

向量和矩阵

Variables变量可以是标量、向量、矩阵,意味着它可以是0,1,2维

#A scalar variable.
a = cvx.Variable()
# Vector variable with shape (5,).
x = cvx.Variable(5) 列向量,5维

# Matrix variable with shape (5, 1).
x = cvx.Variable((5, 1))

# Matrix variable with shape (4, 7).
A = cvx.Variable((4, 7))

你可以使用python本身的数值库来构造矩阵与向量常数,For instance, if x is a CVXPY Variable in the expression A*x + b, A and b could be Numpy ndarrays, SciPy sparse matrices, etc. A and b could even be different types.
Currently the following types may be used as constants:
NumPy ndarrays
NumPy matrices
SciPy sparse matrices
看如下例子:


// Solves a bounded least-squares problem.
import cvxpy as cvx
import numpy
// Problem data.
m = 10
n = 5
numpy.random.seed(1)
A = numpy.random.randn(m, n)矩阵A
b = numpy.random.randn(m)向量b
//变量xx是一个向量
x = cvx.Variable(n)
objective = cvx.Minimize(cvx.sum_squares(A*x - b))
constraints = [0 <= x, x <= 1]
prob = cvx.Problem(objective, constraints)
print("Optimal value", prob.solve())
print("Optimal var")
print(x.value) # A numpy ndarray.
  Optimal value 4.14133859146
  Optimal var
  [ -5.11480673e-21   6.30625742e-21   1.34643668e-01   1.24976681e-01
-4.79039542e-21]

约束

正如上述代码所写,你能够使用==,<=和>=去构造约束条件。无论是否是标量、向量以及矩阵,约束是元素性质的,For example, the constraints 0 <= x and x <= 1 mean that every entry of x is between 0 and 1.
你不能使用>与<构造不等式

参数Parameters

Parameters are symbolic representations of constants. The purpose of parameters is to change the value of a constant in a problem without reconstructing the entire problem.参数是常量的符号表示,参数存在的目的是:不用重新构造整个问题而改变一个问题常量的值。
参数可以是向量或者是矩阵,就像变量一样。当你创建一个参数时,可以指明参数的属性,例如参数的正负,参数的对称性等,Parameters can be assigned a constant value any time after they are created.

# Positive scalar parameter.
m = cvx.Parameter(nonneg=True)
# Column vector parameter with unknown sign (by default).
c = cvx.Parameter(5)
# Matrix parameter with negative entries.
G = cvx.Parameter((4, 7), nonpos=True)
# Assigns a constant value to G.
G.value = -numpy.ones((4, 7))

You can initialize a parameter with a value. The following code segments are equivalent:
# Create parameter, then assign value.
rho = cvx.Parameter(nonneg=True)
rho.value = 2
# Initialize parameter with a value.
rho = cvx.Parameter(nonneg=True, value=2)
  //实例代码:
Computing trade-off curves is a common use of parameters. The example below computes a trade-off curve for a LASSO problem.

import cvxpy as cvx
import numpy
import matplotlib.pyplot as plt

# Problem data.
n = 15
m = 10
numpy.random.seed(1)
A = numpy.random.randn(n, m)
b = numpy.random.randn(n)
# gamma must be nonnegative due to DCP rules.
gamma = cvx.Parameter(nonneg=True)

# Construct the problem.
x = cvx.Variable(m)
error = cvx.sum_squares(A*x - b)
obj = cvx.Minimize(error + gamma*cvx.norm(x, 1))
prob = cvx.Problem(obj)

sq_penalty = []
l1_penalty = []
x_values = []
gamma_vals = numpy.logspace(-4, 6)
for val in gamma_vals:
    gamma.value = val
    prob.solve()
    # Use expr.value to get the numerical value of
    # an expression in the problem.
    sq_penalty.append(error.value)
    l1_penalty.append(cvx.norm(x, 1).value)
    x_values.append(x.value)

plt.rc('text', usetex=True)
plt.rc('font', family='serif')
plt.figure(figsize=(6,10))

# Plot trade-off curve.
plt.subplot(211)
plt.plot(l1_penalty, sq_penalty)
plt.xlabel(r'\|x\|_1', fontsize=16)
plt.ylabel(r'\|Ax-b\|^2', fontsize=16)
plt.title('Trade-Off Curve for LASSO', fontsize=16)

# Plot entries of x vs. gamma.
plt.subplot(212)
for i in range(m):
    plt.plot(gamma_vals, [xi[i] for xi in x_values])
plt.xlabel(r'\gamma', fontsize=16)
plt.ylabel(r'x_{i}', fontsize=16)
plt.xscale('log')
plt.title(r'\text{Entries of x vs. }\gamma', fontsize=16)

plt.tight_layout()
plt.show()

转载自原文链接, 如需删除请联系管理员。

原文链接:Python.CVXPY学习指南一,转载请注明来源!

0