一、CVX问题
1.简单实例
import cvxpy as cp
# Create two scalar optimization variables.
x = cp.Variable()
y = cp.Variable()
# Create two constraints.
constraints = [x + y == 1,
x - y >= 1]
# Form objective.
obj = cp.Minimize((x - y)**2)
# Form and solve problem.
prob = cp.Problem(obj, constraints)
# Returns the optimal value.
prob.solve()
print("status:", prob.status)
print("optimal value", prob.value)
print("optimal var", x.value, y.value)
定义好优化变量、约束与目标函数、优化问题之后,调用prob.solve()函数即可以解决问题,函数会返回最优值并更新prob.state,prob.value 和 所有变量的值。
上述例子的输出应为:
status: optimal
optimal value 0.999999999761
optimal var 1.00000000001 -1.19961841702e-11
2.修改问题
值得注意的是,一旦优化问题被定义后就不可进行修改。
若需要对当前优化问题的目标函数后约束进行改动的话,需要创建一个新的问题。
# Replace the objective.
prob2 = cp.Problem(cp.Maximize(x + y), prob.constraints)
print("optimal value", prob2.solve())
# Replace the constraint (x + y == 1).
constraints = [x + y <= 3] + prob2.constraints[1:]
prob3 = cp.Problem(prob2.objective, constraints)
print("optimal value", prob3.solve())
输出为:
optimal value 1.0
optimal value 3.00000000006
3.问题无解
若问题无解,如可行域为空或无边界时,调用.solve()进行解决时,无法得到最优解,同时问题变量的值空间也不会被修改,示例如下:
import cvxpy as cp
x = cp.Variable()
# An infeasible problem.
prob = cp.Problem(cp.Minimize(x), [x >= 1, x <= 0])
prob.solve()
print("status:", prob.status)
print("optimal value", prob.value)
# An unbounded problem.
prob = cp.Problem(cp.Minimize(x))
prob.solve()
print("status:", prob.status)
print("optimal value", prob.value)
输出为:
status: infeasible
optimal value inf
status: unbounded
optimal value -inf
二、Variables & Parameters
1.变量与常量
使用Variables()定义问题优化变量,如下:
# A scalar variable.
a = cp.Variable()
# Vector variable with shape (5,).
x = cp.Variable(5)
# Matrix variable with shape (5, 1).
x = cp.Variable((5, 1))
# Matrix variable with shape (4, 7).
A = cp.Variable((4, 7))
目前,可以使用以下类型作为常量:
- NumPy ndarrays
- NumPy matrices
- SciPy sparse matrices
示例如下:
# Solves a bounded least-squares problem.
import cvxpy as cp
import numpy
# Problem data.
m = 10
n = 5
numpy.random.seed(1)
A = numpy.random.randn(m, n)
b = numpy.random.randn(m)
# Construct the problem.
x = cp.Variable(n)
objective = cp.Minimize(cp.sum_squares(A @ x - b))
constraints = [0 <= x, x <= 1]
prob = cp.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]
2.参数
参数是常量的符号表示,其目的是为了在不重构整个问题的情况下改变问题中的一个常数的值。毕竟,在大多数情况下,多次解决一个参数化程序比反复解决一个新问题要快得多。
参数可被创建为向量或矩阵,也可指定其属性,例如参数条目的符号、参数是否对称等。参数可在创建时被赋值,也可以在被创建后的任何时候赋值为某一个常数,但该常数必须与创建参数时指定的尺寸和属性相同。
# Positive scalar parameter.
m = cp.Parameter(nonneg=True)
# Column vector parameter with unknown sign (by default).
c = cp.Parameter(5)
# Matrix parameter with negative entries.
G = cp.Parameter((4, 7), nonpos=True)
# Assigns a constant value to G.
G.value = -numpy.ones((4, 7))
# Initialize parameter with a value.
rho = cp.Parameter(nonneg=True, value=2)
计算权衡曲线是参数的常用用法,示例如下:
import cvxpy as cp
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 = cp.Parameter(nonneg=True)
# Construct the problem.
x = cp.Variable(m)
error = cp.sum_squares(A @ x - b)
obj = cp.Minimize(error + gamma*cp.norm(x, 1))
prob = cp.Problem(obj)
# Construct a trade-off curve of ||Ax-b||^2 vs. ||x||_1
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(cp.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()
通过参数化问题,我们可以在上面的LASSO问题中并行计算每个γ的最优x:
from multiprocessing import Pool
# Assign a value to gamma and find the optimal x.
def get_x(gamma_value):
gamma.value = gamma_value
result = prob.solve()
return x.value
# Parallel computation (set to 1 process here).
pool = Pool(processes = 1)
x_values = pool.map(get_x, gamma_vals)