赞
踩
linprog函数可以求解线性等式约束和不等式约束下的最小目标值问题。这类问题就是众所周知的线性规划。线性规划可以解决以下形式的问题:
m
i
n
x
c
T
x
s
u
c
h
t
h
a
t
A
u
b
x
≤
b
u
b
,
A
e
q
x
=
b
e
q
,
l
≤
x
≤
u
,
\mathop{min}\limits_{x} \ c^{T}x \\ {\rm such \ that} \ A_{ub}x \leq b_{ub}, \\ A_{eq}x = b_{eq }, \\ l \leq x \leq \ u,
xmin cTxsuch that Aubx≤bub,Aeqx=beq,l≤x≤ u,
其中
x
x
x是一个决策变量向量;
c
,
b
u
b
,
b
e
q
,
l
,
u
c,b_{ub},b_{eq},l,u
c,bub,beq,l,u是向量;
A
u
b
,
A
e
q
A_{ub},A_{eq}
Aub,Aeq是矩阵。在本教程中,我们将尝试使用 linprog 解决一个典型的线性规划问题。
考虑下面这个简单的线性规划问题:
m
a
x
x
1
,
x
2
,
x
3
,
x
4
29
x
1
+
45
x
2
s
u
c
h
t
h
a
t
x
1
−
x
2
−
3
x
3
≤
5
2
x
1
−
3
x
2
−
7
x
3
+
3
x
4
≥
10
2
x
1
+
8
x
2
+
x
3
=
60
4
x
1
+
4
x
2
+
x
4
=
60
0
≤
x
0
0
≤
x
1
≤
5
x
2
≤
0.5
−
3
≤
x
3
\mathop{max}\limits_{x_{1},x_{2},x_{3},x_{4}} 29x_{1} + 45x_{2} \\ {\rm such \ that} \ x_{1} - x_{2} - 3x_{3} \leq 5 \\ 2x_{1} - 3x_{2} - 7x_{3} + 3x_{4} \geq 10 \\ 2x_{1} + 8x_{2} + x_{3} = 60 \\ 4x_{1} + 4x_{2} + x_{4} = 60 \\ 0 \leq x_{0} \\ 0 \leq x_{1} \leq 5 \\ x_{2} \leq 0.5 \\ -3 \leq x_{3}
x1,x2,x3,x4max29x1+45x2such that x1−x2−3x3≤52x1−3x2−7x3+3x4≥102x1+8x2+x3=604x1+4x2+x4=600≤x00≤x1≤5x2≤0.5−3≤x3
我们需要进行一些数学操作,将目标问题转换成 linprog 可以接受的形式。
首先,我们来看看目标函数。我们希望最大化目标函数,但 linprog 只能接受最小化问题。将最大化
29
x
1
+
45
x
2
29x_{1} + 45x_{2}
29x1+45x2转换为最小化
−
29
x
1
−
45
x
2
-29x_{1} - 45x_{2}
−29x1−45x2,就很容易解决这个问题。另外,目标函数中没有显示
x
3
,
x
4
x_{3},x_{4}
x3,x4。这意味着与
x
3
,
x
4
x_{3},x_{4}
x3,x4对应的权重为零。因此,目标函数可以转换为:
m
i
n
x
1
,
x
2
,
x
3
,
x
4
−
29
x
1
−
45
x
2
+
0
x
3
+
0
x
4
\mathop{min}\limits_{x_{1},x_{2},x_{3},x_{4}} -29x_{1} - 45x_{2} + 0x_{3} + 0x_{4}
x1,x2,x3,x4min−29x1−45x2+0x3+0x4
如果我们定义决策变量$ x = [x_{1},x_{2},x_{3},x_{4}]^{T}
的向量,那么在这个问题中,
l
i
n
p
r
o
g
的目标权重向量
的向量,那么在这个问题中,linprog 的目标权重向量
的向量,那么在这个问题中,linprog的目标权重向量c$应该是
c
=
[
−
29
,
−
45
,
0
,
0
]
T
c = [-29,-45,0,0]^{T}
c=[−29,−45,0,0]T
接下来,我们来看看两个不等式约束。第一个不等式是“小于”不等式,所以它已经是 linprog 接受的形式。第二个不等式是“大于”不等式,因此我们需要将两边乘以-1,将其转换为“小于”不等式。明确显示零系数后,我们得到:
x 1 − x 2 − 3 x 3 + 0 x 4 ≤ 5 − 2 x 1 + 3 x 2 + 7 x 3 − 3 x 4 ≤ − 10 x_{1} - x_{2} - 3x_{3} + 0x_{4} \leq 5 \\ -2x_{1} + 3x_{2} + 7x_{3} - 3x_{4} \leq -10 x1−x2−3x3+0x4≤5−2x1+3x2+7x3−3x4≤−10
这些方程可以转换成矩阵形式:
A u b x ≤ b u b A_{ub}x \leq b_{ub} Aubx≤bub
其中
A
u
b
=
[
1
−
1
−
3
0
−
2
3
7
−
3
]
b
u
b
=
[
5
−
10
]
A_{ub} =
接下来,我们来看看两个相等约束条件。明确显示权重为零的是:
2 x 1 + 8 x 2 + 1 x 3 + 0 x 4 = 60 4 x 1 + 4 x 2 + 0 x 3 + 1 x 4 = 60 2x_{1} + 8x_{2} + 1x_{3} + 0x_{4} = 60 \\ 4x_{1} + 4x_{2} + 0x_{3} + 1x_{4} = 60 2x1+8x2+1x3+0x4=604x1+4x2+0x3+1x4=60
这些方程可以转换成矩阵形式:
A e q x = b e q A_{eq}x = b_{eq} Aeqx=beq
其中
A
e
q
=
[
2
8
1
0
4
4
0
1
]
b
e
q
=
[
60
60
]
A_{eq} =
最后,让我们考虑对单个决策变量的单独不等式约束,即所谓的“边界约束”或“简单约束”。这些约束可以通过linprog的界限参数来应用。正如linprog文档中所指出的,边界的默认值是0或无,这意味着每个决策变量的下限都是0,而每个决策变量的上限都是无穷大:所有的决策变量都是非负的。我们的界限是不同的,因此需要将每个决策变量的下限和上限指定为一个元组,并将这些元组组合成一个列表。
最后,我们可以使用 linprog 解决转换后的问题。
import numpy as np
from scipy.optimize import linprog
c = np.array([-29.0, -45.0, 0.0, 0.0])
A_ub = np.array([[1.0, -1.0, -3.0, 0.0],
[-2.0, 3.0, 7.0, -3.0]])
b_ub = np.array([5.0, -10.0])
A_eq = np.array([[2.0, 8.0, 1.0, 0.0],
[4.0, 4.0, 0.0, 1.0]])
b_eq = np.array([60.0, 60.0])
x0_bounds = (0, None)
x1_bounds = (0, 5.0)
x2_bounds = (-np.inf, 0.5) # +/- np.inf can be used instead of None
x3_bounds = (-3.0, None)
bounds = [x0_bounds, x1_bounds, x2_bounds, x3_bounds]
result = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
print(result.message)
The problem is infeasible. (HiGHS Status 8: model_status is Infeasible; primal_status is At lower/fixed bound)
结果表明,我们的问题是不可行的,即没有满足所有约束条件的解向量。这并不一定意味着我们做错了什么,有些问题确实是不可行的。
然而,假设我们决定对
x
1
x_{1}
x1的边界约束太紧,可以放宽到
0
≤
x
1
≤
6
0\leq x_{1}\leq 6
0≤x1≤6。接下来调整我们的代码 x1_bounds = (0,6)以反应更改并再次执行它:
x1_bounds = (0, 6)
bounds = [x0_bounds, x1_bounds, x2_bounds, x3_bounds]
result = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds)
print(result.message)
Optimization terminated successfully. (HiGHS Status 7: Optimal)
结果显示优化成功。我们可以检查目标值(result.fun)是否与 c T x c^{T}x cTx相同:
x = np.array(result.x)
obj = result.fun
print(c @ x)
-505.974358974359
print(obj)
-505.974358974359
我们还可以检查所有约束条件是否在合理的公差范围内得到满足:
print(b_ub - (A_ub @ x).flatten()) # this is equivalent to result.slack
[ 0.00000000e+00 -7.10542736e-15]
print(b_eq - (A_eq @ x).flatten()) # this is equivalent to result.con
[-7.10542736e-15 0.00000000e+00]
print([0 <= result.x[0], 0 <= result.x[1] <= 6.0, result.x[2] <= 0.5, -3.0 <= result.x[3]])
[True, True, True, True]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。