补充数学 - 单纯形法

一、总论

单纯形法十分神奇,涉及的理论并不困难,但是很复杂。而且不但理论繁琐,而且算法有变得极具有 “跳大神色彩”,“单纯性表、检验系数” 等一系列玄学名词让人作呕(从我和我妈打交道的经历来看,经济学一定说一些非人话的东西,才可以满意)。更加痛苦的是,它是线性代数知识的应用,我对于线代的理解就是,“挟泰山以超北海”,很多复杂的东西被用线代知识简化成了 “魔数” 一样的东西,课本并不会详细说为啥是这样的,他们只会说大概可以用线代知识表示成这样。


二、线代知识复习

对于一个线性方程组,我们可以将其转换成矩阵形式,也就是

Ax=bAx = b

的形式,其中我们对于 AA 的考察变得很有趣,如果 AA 是一个满秩矩阵,那么就很容易,必然存在唯一解 xx。但是如果 AA 不是满秩的,那么它就会导致 xx 是多解的,多解就意味着有一个解空间,不幸的是,这个解空间都是可以求的(所以才这么多麻烦事)。

对于 Ax=bAx = b 的求解,首先是解出一个特解来。特解需要先利用高斯消元来化简矩阵为阶梯矩阵,然后变成阶梯矩阵之后,就可以很容易将阶梯角的列向量挑出来,他们对应的解的分量是必须的,对于非阶梯的地方,我们就让他们对应的解的分量为 0 ,然后就可以解出特解来了。

然后我们求出 Ax=0Ax = 0 的解平面,然后就可以 “通解 + 特解” 了。这个部分我写的很潦草,是因为我本来就不具备把他写好的能力。

之所以复习这里,是因为线性规划设计到的就是一个 Ax=bAx = b 形式的方程,而且其中 AA 不满秩,这才导致 xx 具有多解,而线性规划描述的,正是在这多个解中,调出我们需要的那个最优解 x0x_0 的事情。


三、线性规划原理

让我们关注本质,忽略一下如何把不太规范的线性规划转换成规范的线性规划,我们直接看规范的线性规范,描述的是这样的一个东西,有 Ax=b,x>0Ax = b, x > 0 的约束条件(同时有 AA 不满秩,满秩就直接解出来 xx 了),要求 z=cxz = cx 的最大值或者最小值。

然后经过某个神秘的定理,我们获得了一个有用的信息,就是 xx 虽然可以取很无数个值,但是有可能是最优解,只会发生在某些特定的情况下,当我们解线性方程组特解的时候,用到了这个方法

就可以很容易将阶梯角的列向量挑出来,他们对应的解的分量是必须的,对于非阶梯的地方,我们就让他们对应的解的分量为 0 ,然后就可以解出特解来了

概括一下就是,因为 AA 不满秩,所以可以拆成一个满秩的矩阵(基向量组),和一堆非基向量,然后让非基向量对应的变量为 0,就可以求出特解。但是非基向量是被挑出来的,有很多种挑法,这就导致会有很多的特解。我们的定理告诉我们

最优解一定在这堆特解中。

如果 AAm×nm\times n 维的,那么这堆特解的个数就是 CnmC^{m}_{n} 个。我们只要尝试了这么多次,就可以把这个问题解决了。但是显然这太愚蠢了。所以我们发明了单纯形法,这个方法可以让我们更快的找到最优解。


四、单纯形法

在开始介绍单纯形法之前,一定要强调,我并没有完全弄懂这个东西,哪怕跳过了证明,但看思路,也是没有完全弄懂,所以我不认为在期末的时候,我可以把他搞懂。

单纯形法就是靠着不断的换入和换出基变量,来最终确定那个最优解的基变量组的。我们首先挑选出 “入基变量”,根据的是将 zz 表达成只含非基变量的线性表达式完成的,然后通过判断非基变量前系数的正负来判断各种东西。至于为啥可以,虽然书上解释了一大堆,但是我没有看懂,而且我觉得看不懂了。至于这个前面的系数,被称作 检验数 σ\sigma

可以再补充一下,这个检验数可以看做是用基变量表示目标函数的时候,基变量前的系数(鬼知道为什么要故弄玄虚),之所以叫做检验数,是因为它可以判断这个算法是否终结(这也很显然,当系数都为负数或者都为正数的时候,就该停止了)。

这里插入一段,我跟香老师说了这件事情,香老师帮我解释清楚了。

我们的 zz 长成这样

z=a1x1+a2x2+...am+1xm+1+anxn+cz = a_1x_1 + a_2x_2 + ... a_{m + 1} x_{m + 1}+ a_nx_n + c

我们可以通过 Ax=bAx = b 这个关系,用非基变量表示基变量,变成这种东西

z=am+1xm+1+...anxn+cz = a_{m+1}x_{m + 1} + ... a_nx_n + c^{'}

但是我们又约定了,非基变量只能是 0,所以这次的 zz 的取值就是 cc^{'} 。我们如果不让某个非基变量为 0,那么 zz 可以更大,但是我们让其不为零的方法就是让它称为基变量。也就是 “换入”。

其次确定 “出基变量”,根据的是一个叫做 θ\theta 规则的东西,说白了就是让所有的基变量都为 0,进而求出入基变量的最大值,我们当然希望入基变量越大越好,但是无限制的大会导致其他基变量的取值变成负数,这就不符合题义了。所以我们才让所有的基变量为 0(可以被看做是负数的边界),然后去求 θ\theta,我们会挑出 “非负的,最小的”(很容易想到为什么是这个条件)的 θ\theta 对应的基变量,然后让它成为非基变量。

此外,对于求解最大值和最小值的问题,其实需要修改的只有对于 σ\sigma 的判断,并不涉及对于 θ\theta 判断规则的改变,这也是非常显然的事情。

然后经过这么愚蠢的直观理解后,到了记录单纯形法过程的环节。


五、实现

首先看题面

max z=2x1+3x2+0x3+0x4+0x5max \space z = 2x_1 + 3x_2 + 0x_3 + 0x_4 + 0x_5

{1x1+2x2+1x3+0x4+0x5=84x1+0x2+0x3+1x4+0x5=160x1+4x2+0x3+0x4+1x5=12x1,x2,x3,x4,x50\begin{cases} 1x_1 + 2x_2 + 1x_3 + 0x_4 + 0x_5 = 8 \\ 4x_1 + 0x_2 + 0x_3 + 1x_4 + 0x_5 = 16 \\ 0x_1 + 4x_2 + 0x_3 + 0x_4 + 1x_5 = 12 \\ x_1, x_2, x_3, x_4, x_5 \geq 0 \end{cases}

我们根据这个表可以填出下面这张表

image-20221008233701717

其中最上面 c 这一列表示变量的价值系数,就是 max z=2x1+3x2+0x3+0x4+0x5max \space z = 2x_1 + 3x_2 + 0x_3 + 0x_4 + 0x_5 各个 xx 前各个系数,这里写定了就不会变了

image-20221008234210641

底下是一个增广矩阵,之后的入基操作和出基操作本质都是行变换,这个部分就是行变换的部分,就是需要跟着行更新的东西。

image-20221008235407358

然后我们来填写一下基向量部分,在这个表里,下标是 BB 的量,都是与基向量有关的。从图可知道,基向量是 x3,x4,x5x_3, x_4, x_5XBX_B 这一项说明了这个东西

image-20221008235738956

CBC_B 这一项是 XBX_B 各个分量对应的价值系数,是随着 XBX_B 变化的。

image-20221009000441530

然后这个表里所有直观的东西就都填完了,现在我们要计算 θj\theta_jjj 下标的意思就是每列(也就是每个变量)都会有这样的一个东西。其计算公式是

θj=cjzj\theta_j = c_j - z_j

cjc_j 是价值系数,很显然,zjz_j 就没有那么直观,它本质是用非基变量代替基变量的过程,发生了系数的改变,其算式是 zj=CBPjTz_j = C_B P_j^{T} 。也就是这下面两个变量的相乘

image-20221009001509678

按照这个规则将 σj\sigma_j 填好,有如下示例

image-20221009001619855

然后就必须审视一遍所有的 σ\sigma ,如果所有的 σ\sigma 都小于等于 0,事情就结束了。如果没有,那么我们就需要看看所有的非基变量对应的列向量 PjP_j ,如果存在某个 Pj0P_j \leq 0 。那么这个问题是无界的,否则就可以进行下一步了。

我们挑出 σ\sigma 最大的那个非基变量,他就是入基变量了。在这道题中,就是 x2x_2

image-20221009002228406

我们需要根据入基变量 x2x_2,确定出基变量,确定方法就是利用 θ\theta ,计算方法是 θ=b÷P2\theta = b \div P_2 。其中 ÷\div 是对应项相除的意思,有

image-20221009002511573

然后我们需要挑出最小的 θ\theta ,找到对应的基变量,也就是 x5x_5 。这就是出基变量

image-20221009003004273

现在我们确定了出基变量 x5x_5 和入基变量 x2x_2 。现在需要利用行变换知识将其一个转换为基变量,另一个就顺其自然变成了非基变量。

首先归一化

image-20221009003648188

然后将 P2P_2 其他分量都搞成 0,即

image-20221009003718426

因为基向量发生了改变,所以建立在其上的 XB,CB,σj,θX_B, C_B, \sigma_j, \theta 都需要重新计算,也就是下面这张表

image-20221009004203730

入基变量是 x1x_1 出基变量是 x3x_3 。然后继续进行行变换,并且更新 XB,CB,σj,θX_B, C_B, \sigma_j, \theta ,有

image-20221009004555612

继续迭代

image-20221009004853146

计算完 σ\sigma 之后就会发现均为负数,所以就可以停止迭代了,冷知识,现在的 bb 值就是我们 (x1,x5,x2)(x_1, x_5, x_2) 的值。


六、课设实现

课设实现相较于原有实现要更加简单,表项更少,但是并没有实际降低算法的难度,所以实际效果是一样的。课设删掉了 θ\theta 这一列,并且将 bb 这一列移到了最右侧,这个是我不支持的,因为只是改变了位置,并没有降低难度,而且甚至更加恶心了。同时它合并了 cj,cjzjc_j, c_j - z_j 这两行,这是很好的体现,因为确实计算 cjzjc_j - z_j 是一个不直观的东西,现在变得直观了。

这是例题:

image-20221213235151972

首先要将其变成标准形式,也就是下面的状态

image-20221214001950769

一定要让不等式组变成一组等式,所以才有了新的变量的增加,对于 \leq 的式子变成具有非负右端项的等式(也就是上面的 4 个式子),引入的变量被称为 “松弛变量”,如果是 \geq 的式子,则称为**“剩余变量”**。

然后我们来做表,在做表前还是需要指出,因为有 4 个方程,所以有 4 个基变量。刚好我们对于每个方程都引入了一个松弛变量,这 4 个松弛变量刚好可以组成一组基变量(后面就会发现,不是每次都这么容易的)。

image-20221214002345557

可以看到第二行填写的是目标方程的系数的相反数 z=5x1+4x2+0s1+0s2+0s3+0s4z = 5x_1 + 4x_2 + 0s_1 + 0s_2 + 0s_3 + 0s_4

image-20221214002507593

然后右侧指明了基变量(还是强调,并不是每次都可以这么好运)

image-20221214002609333

其他的系数十分显然。

然后我们需要判断是否可以终止运算(因为单纯形法是一个迭代过程),之前是靠检验数,现在靠目标函数的系数,因为求的是最大值,所以要看系数中有没有负数(也就是实际的正数),如果有,那么说明迭代还没有结束,那么选择最小的负数(其实是选择最大的正数),作为入基变量(系数非零说明对应的变量是非基变量,很显然)。所以这次我们选择 x1x_1

image-20221214003548256

选择离基变量的时候,要保证基变量都是正数,所以做如下运算

image-20221214004147076

然后选择 s1s_1 作为离基变量,因为我们只考虑最小的正数

image-20221214004301832

然后选择好,就可以进行无聊的行变换了,需要注意的是,第 2 行和第 8 列也是需要参与运算的,这是相比于原方法高明的地方,让形式更加统一

image-20221214004928599

然后发现依然是可以继续进行的,因为对于 x2x_2 依然是可以移入的,(原来判断入基变量的叫做最优性条件,判断离基变量的叫做可行性条件):

image-20221214005206868

然后经过行变换,就得到了最终的结果

image-20221214005336540

这是因为现在所有的系数都是正的了,没有办法让 zz 更大了。

后面课件里的第 2 列其实是多余的,去掉就好了。

最后关于判断的总结

image-20221214005450209


七、大 M 法

虽然教材中叫做 “改进 “,但是实际上是,如果不采用下面这两种方法,就会变得没有办法实现,比如说下面的例子

image-20221214010654263

将其转换为标准形式,如下所示

image-20221214010830900

然后发现,没有初始解(就是没有显然的基变量),那么就需要再次引入变量 R1,R2R_1, R_2,他们被称为人工变量

image-20221214010947009

但是人工变量并不是无条件加入的,我们要保证 R1=0,R2=0R_1 = 0, R_2 = 0 最终在最优解中成立,所以我们需要指定一个规则,其具体体现就是 M 无穷大(在最小化目标中,如果是最大化目标,就是无穷小):

image-20221214011236184

但是此时会发现这个表依然没有办法使用,因为我们需要的是在第二行,只有非基变量前有非 0 系数,现在 R1,R2R_1, R_2 都是基变量,但是他们前面有系数,所以利用行变换,让其为 0(利用第 3,4 行)。如下所示

image-20221214011608543

image-20221214011558885

然后就可以进行正常的单纯形法。


八、退化问题

退化问题最重要的是可能陷入局部最优解,也就是不是最优解的意思,所以一定要尽力避免退化。

image-20221217104110456

导致退化的原因可以看做是当选择出基变量的时候,多个基变量的 θ\theta 具有相同的值,那么无论挑选哪一个,在经过行变换后,都会导致基变量的值为 0(以后每次都会选择这个位置(这一行)作为出基变量,因此这个位置计算出的 θ\theta 恒为 0 ),这就导致无法更新最终的目标值。如下所示

image-20221217104339158