单纯形算法 Simplex Algorithm (二)

为了真正理解单纯形算法的具体步骤,我查阅了许多文章,不过大部分文章会直接叙述单纯形表的操作,对理解算法帮助有限;也有一些文章直接从线性代数上的原理开始叙述,对于非专业人士又太难了。所幸我找到了一个挺不错的在线课程,感觉是我看过叙述单纯形算法最明了直观的资料了,下面的内容主要就是对这个课程的翻译

初始可行解

我们直接就用个例子来叙述算法。还是上一篇的例子:
m a x Z = 40 x 1 + 50 x 2 s . t . x 1 + 2 x 2 ≤ 40 4 x 1 + 3 x 2 ≤ 120 x 1 , x 2 ≥ 0 \begin{aligned} max\quad& Z=40x_1+50x_2\\ s.t.\quad& x_1+2x_2\leq40 \\ & 4x_1+3x_2\leq120 \\ & x_1,x_2\geq0 \end{aligned} maxs.t.Z=40x1+50x2x1+2x2404x1+3x2120x1,x20
把它松弛化:
m a x Z = 40 x 1 + 50 x 2 s . t . x 1 + 2 x 2 + s 1 = 40 4 x 1 + 3 x 2 + s 2 = 120 x 1 , x 2 , s 1 , s 2 ≥ 0 \begin{aligned} max\quad& Z=40x_1+50x_2\\ s.t.\quad& x_1+2x_2+s_1=40 \\ & 4x_1+3x_2+s_2=120 \\ & x_1,x_2,s_1,s_2\geq0 \end{aligned} maxs.t.Z=40x1+50x2x1+2x2+s1=404x1+3x2+s2=120x1,x2,s1,s20
在上一篇文章中我是以分块矩阵的形式来表现基变量和非基变量,这里我们有更加直观和简单的方法:把约束方程组中的基变量统一移到等式左侧,非基变量统一移到等式右侧,而目标则通过消元操作用非基变量表示:
m a x Z = 40 x 1 + 50 x 2 s . t . s 1 = 40 − x 1 − 2 x 2 s 2 = 120 − 4 x 1 − 3 x 2 x 1 , x 2 , s 1 , s 2 ≥ 0 \begin{aligned} max\quad& Z=40x_1+50x_2\\ s.t.\quad& s_1=40-x_1-2x_2 \\ & s_2=120-4x_1-3x_2 \\ & x_1,x_2,s_1,s_2\geq0 \end{aligned} maxs.t.Z=40x1+50x2s1=40x12x2s2=1204x13x2x1,x2,s1,s20
然后令非基变量 x 1 = x 2 = 0 x_1=x_2=0 x1=x2=0,则各个基变量则等于各个约束中的常数项,即 s 1 = 40 , s 2 = 120 s_1=40,s_2=120 s1=40,s2=120,目标值 Z = 0 Z=0 Z=0,我们得到一个初始的可行解
x = [ x 1 x 2 s 1 s 2 ] = [ 0 0 40 120 ] \boldsymbol{x}= \begin{bmatrix} x_1\\ x_2\\ s_1\\ s_2 \end{bmatrix}= \begin{bmatrix} 0\\ 0\\ 40\\ 120 \end{bmatrix} x=x1x2s1s2=0040120

解的转移

有了初始可行解,就可以开始整个算法的迭代过程,每次迭代需要有基变量的出基和非基变量的入基。
首先需要选择一个要变成基变量的非基变量,这里我们必须要选择在约束中系数为负数的变量,在这个例子中,我们可以选择变量 x 1 x_1 x1,它在两个约束等式中的系数都是负数:
单纯形算法 Simplex Algorithm (二)_第1张图片
为什么一定要系数为负数? 因为如果是正数,把它移到等式左侧进行规整时等式两边就需要除以一个负数,那么最终约束等式中将存在负数常数项,无法得到可行解。
我们选择了 x 1 x_1 x1作为入基的变量,可以看到两个约束等式都可以让 x 1 x_1 x1移到等式左侧,也就意味着基变量 s 1 s_1 s1 s 2 s_2 s2都是可选的出基变量,我们先随机选择一个来试下效果。先选择让 s 1 s_1 s1出基,即对第一个等式进行互换操作:
s 1 = 40 − x 1 − 2 x 2 ⟹ x 1 = 40 − s 1 − 2 x 2 s_1=40-x_1-2x_2 \\ \Longrightarrow x_1=40-s_1-2x_2 s1=40x12x2x1=40s12x2
然后将 x 1 x_1 x1带入第二个等式来消去里面的 x 1 x_1 x1
s 2 = 120 − 4 x 1 − 3 x 2 ⟹ s 2 = 120 − 4 ( 40 − s 1 − 2 x 2 ) − 3 x 2 ⟹ s 2 = − 40 + 4 s 1 − 3 x 2 s_2=120-4x_1-3x_2 \\ \Longrightarrow s_2=120-4(40-s_1-2x_2)-3x_2 \\ \Longrightarrow s_2=-40+4s_1-3x_2 s2=1204x13x2s2=1204(40s12x2)3x2s2=40+4s13x2
这样新的基变量表示为:
x 1 = 40 − s 1 − 2 x 2 s 2 = − 40 + 4 s 1 − 3 x 2 \begin{aligned} & x_1=40-s_1-2x_2 \\ & s_2=-40+4s_1-3x_2 \end{aligned} x1=40s12x2s2=40+4s13x2
但是可以看到变量 s 2 s_2 s2的等式中常数项为负数,也就是说对应的基解也不可行,说明我们选择 s 1 s_1 s1出基是不可行的;因此选择出基变量不可以随机选择,在这里我们需要采取这样的策略:

  • e e e是入基变量的下标, l l l是出基变量的下标, a i e a_{ie} aie是第 i i i个约束等式中变量 x e x_e xe的系数, b i b_i bi是第 i i i个约束等式中的常数项,那么有
    l = arg min ⁡ i : a i e < 0 b i − a i e \begin{aligned} l= \underset {i:a_{ie}<0} {\operatorname {arg\,min} } \frac{b_i}{-a_{ie}} \end{aligned} l=i:aie<0argminaiebi
    也就是在选择了入基变量 x e x_e xe后,选择各个约束等式中常数项除以系数负值后最小的那个等式对应的基变量

通过这个规则可以确保转移操作后解的可行性。回到我们的例子,在选择 x 1 x_1 x1为入基变量后,分别计算各个 b i − a i e \frac{b_i}{-a_{ie}} aiebi值,可以看到第二个等式的这个值是最小的,所以应该用变量 s 2 s_2 s2来出基
单纯形算法 Simplex Algorithm (二)_第2张图片
经过转换,可以得到:
m a x Z = 1200 − 10 s 2 + 20 x 2 x 1 = 30 − 1 4 s 2 − 3 4 x 2 s 1 = 10 + 1 4 s 2 − 5 4 x 2 \begin{aligned} max\quad& Z=1200-10s_2+20x_2\\ & x_1=30-\frac{1}{4}s_2-\frac{3}{4}x_2 \\ & s_1=10+\frac{1}{4}s_2-\frac{5}{4}x_2 \end{aligned} maxZ=120010s2+20x2x1=3041s243x2s1=10+41s245x2
对应了一个可行解 x 1 = 30 , x 2 = 0 , s 1 = 10 , s 2 = 0 x_1=30,x_2=0,s_1=10,s_2=0 x1=30,x2=0,s1=10,s2=0,目标值为1200
一般我们把这个变量 x e x_e xe和变量 x l x_l xl交换操作称之为 p i v o t ( e , l ) pivot(e,l) pivot(e,l)

验证最优性

我们需要判断当前可行解的目标值是否是最优来停止算法的迭代,这里有这样的判断标准:

  • 如果在经过某个 p i v o t ( e , l ) pivot(e,l) pivot(e,l)后,其消去基变量后目标函数的形式为:
    Z = c 0 + c 1 x 1 + . . . + c n x n Z=c_0+c_1x_1+...+c_nx_n Z=c0+c1x1+...+cnxn
    其系数 c i ≤ 0 , 1 ≤ i ≤ n c_i\leq0, 1\leq i\leq n ci0,1in,则当前的目标是最优,基可行解也是最优解

继续上面的例子,在进行 p i v o t ( x 1 , s 2 ) pivot(x_1,s_2) pivot(x1,s2)后,目标函数的形式为:
Z = 1200 − 10 s 2 + 20 x 2 Z=1200-10s_2+20x_2 Z=120010s2+20x2
可以看到 x 2 x_2 x2的系数为正,这也就意味着如果我们在不违反约束的情况下继续增大 x 2 x_2 x2,目标值仍会更大,所以这时的基可行解 ( x 1 = 30 , x 2 = 0 , s 1 = 10 , s 2 = 0 ) (x_1=30,x_2=0,s_1=10,s_2=0) (x1=30,x2=0,s1=10,s2=0)不是最优的,所以可以继续选择变量进行 p i v o t pivot pivot迭代,并且下一次迭代的非基变量就从目标函数中系数大于零的变量中选择

因为现在只有变量 x 2 x_2 x2的系数为大于零,所以下一次迭代选择变量 x 2 x_2 x2入基;同样应用上面叙述的出基规则,选择变量 s 1 s_1 s1为出基变量:
m a x Z = 1200 − 10 s 2 + 20 x 2 x 1 = 30 − 1 4 s 2 − 3 4 x 2 s 1 = 10 + 1 4 s 2 − 5 4 x 2 \begin{aligned} max\quad& Z=1200-10s_2+20x_2\\ & x_1=30-\frac{1}{4}s_2-\frac{3}{4}x_2 \\ & s_1=10+\frac{1}{4}s_2-\frac{5}{4}x_2 \end{aligned} maxZ=120010s2+20x2x1=3041s243x2s1=10+41s245x2
⟹ m a x Z = 1360 − 16 s 1 − 6 s 2 x 1 = 24 − 2 5 s 2 + 3 5 s 1 x 2 = 8 + 1 5 s 2 − 4 5 s 1 \Longrightarrow \begin{aligned} max\quad& Z=1360-16s_1-6s_2\\ & x_1=24-\frac{2}{5}s_2+\frac{3}{5}s_1 \\ & x_2=8+\frac{1}{5}s_2-\frac{4}{5}s_1 \end{aligned} maxZ=136016s16s2x1=2452s2+53s1x2=8+51s254s1
这时的基可行解为 ( x 1 = 24 , x 2 = 8 , s 1 = 0 , s 2 = 0 ) (x_1=24,x_2=8,s_1=0,s_2=0) (x1=24,x2=8,s1=0,s2=0),目标值为1360;同时可以看到目标函数 Z = 1360 − 16 s 1 − 6 s 2 Z=1360-16s_1-6s_2 Z=136016s16s2中变量所有的系数都小于零,这也就意味着1360就是最优目标值,我们已经找到了问题的最优解。

伪代码

现在可以总结一些单纯形算法的核心过程,如下面的伪代码所示:
w h i l e ∃ 1 ≤ i ≤ n : c i ≥ 0 d o c h o o s e   e   s u c h   t h a t   c e ≥ 0 l = arg min ⁡ i : a i e < 0 b i − a i e p i v o t ( e , l ) \begin{aligned} while\quad&\exist1\leq i\leq n :c_i \geq 0 \quad do\\ &choose\ e\ such\ that\ c_e\geq0\\ &l= \underset {i:a_{ie}<0} {\operatorname {arg\,min} } \frac{b_i}{-a_{ie}}\\ &pivot(e,l) \end{aligned} while1in:ci0dochoose e such that ce0l=i:aie<0argminaiebipivot(e,l)

特殊情况:无界

现在考虑一下一些异常情况。首先看这个例子,假设下面这个优化模型是按照上面的算法过程进行到某一步时的情况:
m a x Z = 6 + 3 x 1 + 3 x 2 x 3 = 1 + 3 x 1 − 2 x 2 x 4 = 2 + 2 x 1 + x 2 x 5 = 3 + x 1 − 3 x 2 x 1 , x 2 , x 3 , x 4 , x 5 ≥ 0 \begin{aligned} max\quad& Z=6+3x_1+3x_2\\ & x_3=1+3x_1-2x_2 \\ & x_4=2+2x_1+x_2\\ & x_5=3+x_1-3x_2\\ & x_1,x_2,x_3,x_4,x_5\geq 0 \end{aligned} maxZ=6+3x1+3x2x3=1+3x12x2x4=2+2x1+x2x5=3+x13x2x1,x2,x3,x4,x50
因为目标函数中 x 1 x_1 x1 x 2 x_2 x2的系数都是正数,都可以选择为入基变量;如果选择 x 1 x_1 x1,再看约束等式中的情况,此时会发现约束等式中所有 x 1 x_1 x1的系数都是正数,这就意味着如果我们不断加大 x 1 x_1 x1的值,目标值也不断加大,同时所有约束都不违反,说明这个问题是无界的,找不到最优解;如果出现无界,那么肯定是最初的问题模型建立存在某些错误,相应的,算法的迭代中也需要加入无界的检查操作

特殊情况:退化

再看下面的例子:
m a x Z = 5 + 3 x 1 + 3 x 2 x 3 = 0 − 3 x 1 − 2 x 2 x 4 = 2 − 2 x 1 + x 2 x 5 = 3 + x 1 − 3 x 2 x 1 , x 2 , x 3 , x 4 , x 5 ≥ 0 \begin{aligned} max\quad& Z=5+3x_1+3x_2\\ & x_3=0-3x_1-2x_2 \\ & x_4=2-2x_1+x_2\\ & x_5=3+x_1-3x_2\\ & x_1,x_2,x_3,x_4,x_5\geq 0 \end{aligned} maxZ=5+3x1+3x2x3=03x12x2x4=22x1+x2x5=3+x13x2x1,x2,x3,x4,x50
第一个约束等式的常数项为零,这时我们如果继续进行pivot操作,常数项为零的等式的基变量会被选择为出基变量,代入到目标函数消元后,会发现目标函数的常数项仍然为5,而选择的那个约束等式转换后的常数项仍为零;继续进行pivot,会陷入这个零的情况,导致死循环,算法无法退出。

我们称这种情况为退化,为了处理这种情况,最常用的一种手段是再进行pivot选择时严格遵循Bland’s Rule:

  • 选择入基变量时,按照字典序选择目标函数中的入基变量,即选择系数为正的变量里小标最小的那个变量;
  • 选择出基变量时,在最小比例规则的基础上,如果多个基变量所在约束方程的比例同时最小,也是按照字典序选择,即选择下标最小的那个变量

Bland’s Rule进一步细化了算法中pivot选择变量的规则,去除所有的随机选择可能,需要注意的是这个规则是为了避免出现退化,而不是从退化情况跳出。

初始解的问题

到这里算法的主体部分已经都明确了,但其实关于算法的初始解我们还没有详细讨论,在上面的例子里我们是默认让初始的松弛形式的松弛变量作为基变量,得到了一个可行解作为初始解,这在大多数情况下是可以的,但是当原始问题约束不等式中存在某个 b i < 0 b_i<0 bi<0时,这样的处理方法将不可行。例如这个线性规划问题:
m a x Z = x 1 + 2 x 2 x 1 + x 2 ≤ 2 − x 1 − x 2 ≤ − 1 x 1 , x 2 ≥ 0 \begin{aligned} max\quad& Z=x_1+2x_2\\ & x_1+x_2\leq 2\\ & -x_1-x_2\leq -1\\ & x_1,x_2\geq 0 \end{aligned} maxZ=x1+2x2x1+x22x1x21x1,x20
它的松弛形式:
m a x Z = x 1 + 2 x 2 x 1 + x 2 + s 1 = 2 − x 1 − x 2 + s 2 = − 1 x 1 , x 2 , s 1 , s 2 ≥ 0 ⟹ m a x Z = x 1 + 2 x 2 s 1 = 2 − x 1 − x 2 s 2 = − 1 + x 1 + x 2 x 1 , x 2 , s 1 , s 2 ≥ 0 \begin{aligned} max\quad& Z=x_1+2x_2\\ & x_1+x_2+s_1=2\\ & -x_1-x_2+s_2=-1\\ & x_1,x_2,s_1,s_2\geq 0 \end{aligned}\\ \Longrightarrow \begin{aligned} \\ max\quad& Z=x_1+2x_2\\ & s_1=2-x_1-x_2\\ & s_2=-1+x_1+x_2\\ & x_1,x_2,s_1,s_2\geq 0 \end{aligned} maxZ=x1+2x2x1+x2+s1=2x1x2+s2=1x1,x2,s1,s20maxZ=x1+2x2s1=2x1x2s2=1+x1+x2x1,x2,s1,s20
这时得到的基解中, s 2 = − 1 s_2=-1 s2=1,这显然不可行。因此在完整的单纯形算法中,解的初始化问题也是非常重要的一步,有两个问题需要在初始化中解决:

  • 该线性规划是否存在可行解
  • 如果有可行解,如何找到一个可行解来启动迭代

关于初始化的详细讨论,我把它放到后面一篇文章中,因为初始化还需要用到另一个非常巧妙的算法。

你可能感兴趣的:(Intelligence,Solution,运筹优化)