线性规划标准模型如下:
min c x \min cx mincx
s.t. A x = b Ax = b Ax=b
x ≥ 0 x\ge 0 x≥0
首先来看最简单的例子:A是一个方阵,比如:
min 2 x 1 + 5 x 2 \min 2x_1+5x_2 min2x1+5x2
s.t. 3 x 1 + 3 x 2 = 6 3x_1+3x_2=6 3x1+3x2=6
4 x 1 + x 2 = 5 4x_1+x_2=5 4x1+x2=5
x 1 , x 2 ≥ 0 x_1,x_2 \ge 0 x1,x2≥0
只有一个确定解,最优值为7。
约束条件不够的时候,表现为A变扁了。这时候的技巧就是,将A竖着切一刀,分离出一个方阵来:
基变量:令 x = ( x B , x N ) x=(x_B,x_N) x=(xB,xN),其中 x B x_B xB满秩,称 x B x_B xB称为基变量, x N x_N xN称为非基变量。
将原问题用基变量重新表达为
min c B x B + c N x N \min c_Bx_B+c_Nx_N mincBxB+cNxN
s.t. B x B + N x N = b Bx_B+Nx_N=b BxB+NxN=b
x B ≥ 0 , x N ≥ 0 x_B\ge 0,x_N\ge 0 xB≥0,xN≥0
极点:令 x x x有 m m m维(秩 m B ≤ m m_B\le m mB≤m),则需要 m m m个等式才能求解,它们的交点称为极点(有时候是极线)。
单纯形法将搜索问题限制在了极点/极线范围内。那么如何找到它们呢?如有 x N = 0 x_N=0 xN=0,则 x x x就是极点了。那么此时有:
主问题可行条件: B − 1 b ≥ 0 B^{-1}b\ge 0 B−1b≥0
主问题极点有很多,哪一个才是最优解呢?除了遍历搜索,还有一种方法:看对偶问题是否可行。上面问题的对偶问题为:
max b y \max by maxby
s.t. y B T ≤ c B T yB^T\le c^T_B yBT≤cBT
y N T ≤ c N T yN^T\le c^T_N yNT≤cNT
B转置后仍然是满秩的方阵,因此等号是可以取到的,极点满足 y B T = c B T yB^T= c^T_B yBT=cBT,那么此时有:
对偶问题可行条件: c B T B − 1 N ≤ c N T c^T_BB^{-1}N\le c^T_N cBTB−1N≤cNT
如果我们基向量拆分出来同时满足上面两个可行条件,那么恭喜找到最优解了:
主问题可行:非基变量=0时,基变量系数 B − 1 b ≥ 0 B^{-1}b\ge 0 B−1b≥0;
对偶问题可行:基变量系数=0时,非基变量系数 c N T − c B T B − 1 N ≥ 0 c^T_N-c^T_BB^{-1}N\ge 0 cNT−cBTB−1N≥0.
定理:线性规划的极点同时满足主问题和对偶问题的可行条件时,这个极点是最优解。
这两个条件非常重要!重要!重要!
定理:线性规划问题的最优解一定是极点或极线,并且满足比相邻极点都要优。
单纯形法的步骤是从一个初始极点出发,不断找到更优的相邻极点,直到找到最优的极点(或极线)。
消去 x B x_B xB得到问题的字典表达,即:
min c B T B − 1 b + ( c N T − c B T B − 1 N ) x N \min c^T_BB^{-1}b+(c^T_N-c^T_BB^{-1}N)x_N mincBTB−1b+(cNT−cBTB−1N)xN
s.t. B − 1 b − B − 1 N x N ≥ 0 B^{-1}b-B^{-1}Nx_N\ge 0 B−1b−B−1NxN≥0
x N ≥ 0 x_N\ge 0 xN≥0
称 ( c N T − c B T B − 1 N ) i (c^T_N-c^T_BB^{-1}N)_i (cNT−cBTB−1N)i为第 i i i个非基变量的残差(reduced cost),如果残差小于0,那么说明这个非基变量还没有满足最优条件。直观上来看,这个非基变量取稍稍大于0的数就可以继续优化目标函数了。我们选择一个基变量和这个非基变量对换,就可以找到更优的相邻极点。
另一种理解方法:残差对应的是对偶问题可行条件,小于0表示对偶问题还不可行,需要继续探索。
接下来的问题是具体选择哪个基变量和哪个非基变量进行对换。我们用启发式原则,每次将负数残差 ( c N T − c B T B − 1 N ) i (c^T_N-c^T_BB^{-1}N)_i (cNT−cBTB−1N)i最小(绝对值最大)的非基变量 x i x_i xi替换为基变量,同时将 ( B − 1 b ( B − 1 N ) i ) j (\frac{B^{-1}b}{(B^{-1}N)_i})_j ((B−1N)iB−1b)j最小值对应的基变量 x j x_j xj替换为非基变量。这个进基/出基的过程称为pivoting。
另一种表达方式是: min z = c x \min z = cx minz=cx,s.t. A x = b Ax = b Ax=b的pivoting是每次找出c中最小数对应的非基变量 x i x_i xi,再找出 b i / A i j b_i/A_{ij} bi/Aij最小的基变量 x j x_j xj进行对换。
如果是max问题,令 c ′ = − c c'=-c c′=−c即可转化为min问题,相对应的,每次pivoting是找出 c ′ c' c′最大值对应的非基变量。
这里假设原问题都是小于等于约束,这样添加松弛变量之后,问题一定有初始可行解;同时假设问题存在有限最优解。特殊情况将在下一节进行处理。代码为:
import numpy as np
def solve():
while max(d[-1][:-1]) > 0:
jnum = np.argmax(d[-1][:-1]) #转入下标
inum = np.argmin(d[:-1,-1]/d[:-1,jnum]) #转出下标
s[inum] = jnum #更新基变量
d[inum]/=d[inum][jnum]
for i in range(bn):
if i != inum:
d[i] -= d[i][jnum] * d[inum]
def printSol():
for i in range(cn - 1):
print("x%d=%.2f" % (i,d[s.index(i)][-1] if i in s else 0))
print("objective is %.2f"%(-d[-1][-1]))
求解问题:max z = x 0 + 14 ∗ x 1 + 6 ∗ x 2 z = x_0+14*x_1+6*x_2 z=x0+14∗x1+6∗x2
s.t.
x 0 + x 1 + x 2 ≤ 4 x_0 + x_1 + x_2 \leq 4 x0+x1+x2≤4
x 0 ≤ 2 x_0 \leq 2 x0≤2
x 2 ≤ 3 x_2 \leq3 x2≤3
3 ∗ x 1 + x 2 ≤ 6 3*x_1 + x_2 \leq 6 3∗x1+x2≤6
添加变量将问题变为标准形,保存到data.txt中:
1 1 1 1 0 0 0 4
1 0 0 0 1 0 0 2
0 0 1 0 0 1 0 3
0 3 1 0 0 0 1 6
1 14 6 0 0 0 0 0
调用代码:
d = np.loadtxt("data.txt", dtype=np.float)
(bn,cn) = d.shape
s = list(range(cn-bn,cn-1)) #基变量列表
solve()
printSol()
运行后输出结果为:
x0=0.00
x1=1.00
x2=3.00
x3=0.00
x4=2.00
x5=0.00
x6=0.00
objective is 32.00
将simplex用代码写出来,才觉得以前纠结那么久的问题原来那么简单。两三行代码能说清楚的事,何必写一堆看得人眼花缭乱的数学公式呢。
另外,线性规划还有一些很基础的理论要掌握好: