线性规划单纯形法精解

单纯形法(Simplex Method)是解决线性规划问题的一种高效且广泛使用的算法。由乔治·丹齐克(George Dantzig)在20世纪40年代提出,这一方法通过系统地检查可行解空间的极点,从而找到最优解。由于其计算效率高,单纯形法迅速成为线性规划问题中最重要和最常用的算法之一。它的应用范围广泛,能够有效解决实际中的大规模优化问题,因此在现代工业和经济管理中扮演着关键角色。

初始单纯形表 迭代后单纯形表

一、单纯形表的消元法建构

线性规划的标准型为

maxz=CX{AX=bX0

其中: Am×n 矩阵, mn 且秩 r(A)=m ,即 A 中至少有一个 m×m 满秩子矩阵。

1.1 求基本可行解的代数消元(最优解判断条件)

不妨设 B=(P1P2Pm) 是线性规划的一个基, 将有关矩阵和向量分块,记 A=(B,N),C=(CB,CN),X=(XB,XN)T ,为求线性规划的基本最优解,先要求线性规划的基本可行解,这样就需将约束中的基变量用非基变量表示出来。
B1 左乘约束方程 AX=b 的两端,得

B1AX=B1(B,N)(XBXN)=B1BXB+B1NXN=B1b

B1BXB+B1NXN=EXB+B1NXN=B1b

其中 E 是单位矩阵。整理, 得

XB=B1bB1NXN

将其代入目标函数中,得

z=CBB1bCBB1NXN+CNXN=CBB1b+(CNCBB1N)XN

z=CBB1b+j=m+1n(cjCBB1Pj)xj

非基变量 xj 前面的系数 cjCBB1Pj 称为变量 xj 的检验数,表示该变量增加或减少一个单位所引起目标函数值的变化,它可以用来判断将 xj 变成基变量后能否改进目标函数值,以后记为 σj=cjCBB1Pj

最优解判定定理:对某基本可行解 XB=B1b 其他 xN=0, 若所有的 σj=cj CBB1Pj0 ,则该解为最优解。

1.2 求基本可行解的矩阵消元

考虑线性方程组 {AX=bz=CX, 其变量为 [Xz], 为便于求解, 整理得方程组 {0z+AX=bz+CX=0, 其增广矩阵见下表, 应用高斯消元法, 求解线性方程组的解。

常数项 z XB XN
b 0 B N (1-1)
0 -1 CB CN (1-2)

B1 左乘方程组(1-1)的两端, 将 XB 的系数化为单位矩阵, 得下表。

常数项 z XB XN
B1b 0 B1B=E B1N (1-3)
0 -1 CB CN

将方程组(1-3)左乘 CB 加到方程(1-2)两边,消元化简得下表。

常数项 z XB XN
B1b 0 B1B=E B1N
CBB1b -1 CBCBB1B=0 CNCBB1N (1-4)

注意式(1-4)中基向量 XB 、非基向量 XN 的系数,它们形式相似,当前者 CBCBB1B=0时,后者即为检验数 CNCBB1N 的矩阵形式。也就是说,用消元法将目标函数中基变量的系数化为零的同时,就会得到非基变量的检验数。事实上, CBCBB1B 也可看成基向量的检验数, 应用消元法后, 当基向量的检验数化为零时, 非基变量的系数 CNCBB1N 就是其检验数。
从上述论述可知, 计算检验数的方法有两种:一是通过公式 σj=cjCBB1Pj 计算得出;二是应用消元法,将目标函数中基向量的系数都化为零时,非基向量的系数就是检验数。这也是单纯表结构的出处。

1.3 单纯形法=逆矩阵法

单纯形法的核心思想是通过变换基本变量和非基本变量,找到一个新的基本可行解,并通过比较检验数判断该解是否为最优解。在单纯形法中,每一个基本可行解都对应着一个基矩阵的逆矩阵。基矩阵是从约束条件系数矩阵中选取的列所构成的矩阵,它的逆矩阵在每次迭代中都要更新。
这个逆矩阵的求解是单纯形法消元过程的核心,因为它直接影响到新解的生成和目标函数的优化。具体来说,当我们选择一个进入基的变量并排除一个离开基的变量时,这相当于对基矩阵进行了一次列替换操作。为了保持计算的有效性,我们需要快速更新逆矩阵。这通常通过一个修正的高斯消元法来完成,使得新基的逆矩阵可以通过旧基的逆矩阵迅速计算出来。
单纯形的每次迭代,都可以使用逆矩阵来计算检验数,从而判断是否可以进一步优化目标函数。检验数的计算过程依赖于逆矩阵,因为检验数用于评估当前解的可行性及其对目标函数的影响。如果所有检验数都满足最优性条件,那么当前解就是最优解;否则,我们需要通过逆矩阵的进一步操作继续迭代。
例1:已知初始单纯形表和最终单纯形表, 试求解以下问题。
(1)在初始单纯形表中找出最优基 B ,在最终单纯形表里找出 B1
(2)完成最终单纯形表。(3) 给出最优解与最优值。

CB XB B1b x1 x2 x3 x4 x5 x6
初始表 0 x4 60 3 1 1 1 0 0
0 x5 10 1 -1 2 0 1 0
0 x6 20 1 1 -1 0 0 1
σj 2 -1 1 0 0 0
最终表 x4 -1 -2
x1 1/2 1/2
x2 -1/2 1/2
σj

确定最优基和B1

  • 最优基 B:从初始基变量x4x5x6 通过单纯形法操作,最终基变量变为x4x1x2
  • B1:通过最终单纯形表的x4x5x6列得到 B1

B1=[11201/21/201/21/2]

计算B1

  • 右端项b=[601020]

B1b=[11201/21/201/21/2][601020]=[10155]

计算最终单纯形表中的列向量
-x3列向量计算:

  • 初始表中x3列为[1,2,1]T

B1[121]=[10.51.5]

因此x3列为[10.51.5]T

计算检验数σj
目标函数为z=2x1x2+x3

  • 基变量的成本系数向量CB=[0,2,1]
变量 Pj σj=cjCBB1Pj 计算过程
x1 [010] 0 2[0,2,1][0 1 0]=0
x2 [001] 0 1[0,2,1][0 0 1]=0
x3 [10.51.5] -1.5 1[0,2,1][1 0.5 1.5]=1.5
x4 [100] 0 0[0,2,1][1 0 0]=0
x5 [10.50.5] -1.5 0[0,2,1][1 0.5 0.5]=1.5
x6 [20.50.5] -0.5 0[0,2,1][2 0.5 0.5]=0.5

最终单纯形表

CB XB B1b x1 x2 x3 x4 x5 x6
最终表 0 x4 10 0 0 1 1 -1 -2
3 x1 15 1 0 0.5 0 1/2 1/2
2 x2 5 0 1 -1.5 0 -1/2 1/2
σj 0 0 -1.5 0 -1.5 -0.5

最优解与最优值

  • 最优解:X=[15501000]T
  • 最优值:z=25

二、单纯形的迭代步骤

例2:对于线性规划问题

 max 2x1+3x2 s.t. 4x1+x2+x3=16x1+x2+x4=6x1,x2,x3,x4>=0

其中, x3x4 是松驰变量。

决策变量:x=[x1x2x3x4]T 是决策变量向量。
目标函数: Max CTx 其中, C=[2300]T 为目标函数的系数向量。
约束条件: Ax=b ,其中 A=[41101101] 是约束系数矩阵。
b=[166]T 是约束右端项向量。因此,标准型的线性规划问题可以表示为:

XB=[x3,x4],XN=[x1,x2],N=[4111],B=[1001],CB=[0,0],CN=[2,3]

初始化令 XN=[0,0]

第一轮迭代:此时 cNcBB1N=[2,3] 因此选择 x2 作为入基变量更为高效,且 θ=min[161,61]=6x2 入基, x4 出基。经过此轮迭代后,各变量如下

xB=[x3,x2],xN=[x1,x4],N=[4011],B=[1101],cB=[0,3],cN=[2,0]

第二轮迭代:此时 cNcBB1N=[5,3] ,选择 x1 作为入基变量更为高效,且

θ=min[164]=4

x2x1=4 并令 x3=0,x1 入基, x3 出基。经过此轮迭代后,各变量如下

xB=[x1,x2],xN=[x3,x4],N=[1001],B=[4111],cB=[2,3],cN=[0,0]

第三轮迭代:此时 cNcBB1N=[1,2] 都小于 0 ,达到收敛条件,此时令 xN=[0,0] 解得 xB=[2,8] 最小值为28。

可行域顶点 迭代路径

例3:求解下面线性模型


初始单纯形表

x1 x2 x3 x4 x5 b θ
约束 1 3 9 1 0 0 540
约束 2 5 5 0 1 0 450
约束 3 9 3 0 0 1 720
目标函数 70 30 0 0 0

判断当前顶点是否是最优解
对于最大化问题,若当前目标函数中的非基变量的系数小于等于0时,则所得的解为最优解。而在当前的例子中,非基变量的系数分别为70和30,意味着在可行域内随着非基变量x1x2的增大,目标函数就会继续增大,因此当前的解不是最优解。故判断当前所得的解是否为最优解时,只需判断目标函数中非基变量的系数是否小于等于0。
进基和出基变量
变量的出基与入基,在几何图像上表现为顶点的变化。入基的规则为选择使目标函数z变化最快的非基变量入基,即选择系数最大且为正数的非基变量入基,故在本例中选择x1入基。出基的规则则需要引入一个新的量θθ=b/aiai为非基变量系数,ai的选择的是刚刚入基的非基变量的系数),选择最小的θ出基。

x1 x2 x3 x4 x5 b θ
约束 1 3 9 1 0 0 540 180
约束 2 5 5 0 1 0 450 90
约束 3 9 3 0 0 1 720 80
目标函数 70 30 0 0 0

第一次迭代,经过x1入基与x5出基的运算后,得到的结果如下所示。

x1 x2 x3 x4 x5 b θ
x3 0 8 1 0 -1/3 300
x4 0 10/3 0 1 -5/9 50
x1 1 1/3 0 0 1/9 80
Z 0 20/3 0 0 -70/9 5600

令非基变量的值为0,则得到第一次迭代的解,如下所示

X=(x1x2x3x4x5)=(800300500)TZ=5600

判断该解是否为最优解(重复第二个步骤,直到是最优解为止),显然由于非基变量x2的检验数大于0,故当前位置还不是最优解,再次重复上面步骤。

三、练习

例4:用单纯表求解下面线性规划

Maxz=2x1x2+x3s.t.{3x1+x2+x360x1x2+2x310x1+x2x320x1,x2,x30

import pandas as pd
import numpy as np

"""
系数矩阵的形式:
       b  x1  x2  x3  x4  x5
obj    0  70  30   0   0   0
x3   540   3   9   1   0   0
x4   450   5   5   0   1   0
x5   720   9   3   0   0   1
①第一行是目标函数的系数;亦即各变量对应的检验数;第2~4行是约束条件的系数
②第一列是约束方程的常数项
③对于目标函数的更新我们同样采用矩阵的变换,所以obj对应的第一列表示的是目标函数的相反数
"""
"""
运行如下代码后得到的结果如下所示
最终的最优单纯性法是:
        b  x1   x2  x3   x4        x5
obj -5700   0  0.0   0 -2.0 -6.666667
x3    180   0  0.0   1 -2.4  1.000000
x2     15   0  1.0   0  0.3 -0.166667
x1     75   1  0.0   0 -0.1  0.166667
目标函数的值: 5700
最优决策变量是:
x1 = 75
x2 = 15
"""

# Initial Simplex tableau, set dtype to float to handle division correctly
matrix = pd.DataFrame(
    data=np.array([
        [0, 2, -1, 1, 0, 0, 0],
        [60, 3, 1, 1, 1, 0, 0],
        [10, 1, -1, 2, 0, 1, 0],
        [20, 1, 1, -1, 0, 0, 1]
    ], dtype=float),  # Explicitly set dtype to float
    index=['obj', 'x4', 'x5', 'x6'],
    columns=['b', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6']
)

# Print the initial tableau
iteration = 1
print(f"第 {iteration} 个单纯性表是:")
print(matrix)

# Continue the iteration until no positive coefficients are in the objective function row
while True:
    # Check the coefficients of the objective function row (检验数)
    c = matrix.iloc[0, 1:]
    
    # Stop if all reduced costs are less than or equal to zero (optimal solution found)
    if c.max() <= 0:
        break
    
    iteration += 1

    # Choose entering variable (the one with the highest positive coefficient)
    in_x = c.idxmax()
    in_x_v = c[in_x]  # Coefficient of the entering variable

    # Choose leaving variable by calculating θ and finding the minimum
    b = matrix.iloc[1:, 0]
    in_x_a = matrix.iloc[1:][in_x]
    
    # Ensure no division by zero, and select the minimum positive theta value
    theta = b / in_x_a
    theta = theta[theta > 0]  # Consider only positive θ values
    
    if theta.empty:  # If theta is empty, break to avoid errors (degenerate case)
        print("No feasible solution found.")
        break
    
    out_x = theta.idxmin()

    # Pivoting: adjust the rows for the entering and leaving variables
    matrix.loc[out_x, :] = matrix.loc[out_x, :] / matrix.loc[out_x, in_x]
    for idx in matrix.index:
        if idx != out_x:
            matrix.loc[idx, :] -= matrix.loc[out_x, :] * matrix.loc[idx, in_x]

    # Update the basis
    basis = matrix.index.tolist()
    basis[basis.index(out_x)] = in_x
    matrix.index = basis

    # Print current tableau
    print(f"第 {iteration} 个单纯性表是:")
    print(matrix)

# Output the final results
print("最终的最优单纯形表是:")
print(matrix)
print("目标函数的值:", -matrix.iloc[0, 0])

# Determine the optimal decision variables
x_count = (matrix.shape[1] - 1) - (matrix.shape[0] - 1)
X = matrix.iloc[0, 1:].index.tolist()[:x_count]
print("最优决策变量是:")
for xi in X:
    if xi in matrix.index:  # Check if the variable is in the current basis
        print(f"{xi} = {matrix.loc[xi, 'b']}")
    else:
        print(f"{xi} = 0")  # If not in basis, the value is zero
第 1 个单纯性表是:
        b   x1   x2   x3   x4   x5   x6
obj   0.0  2.0 -1.0  1.0  0.0  0.0  0.0
x4   60.0  3.0  1.0  1.0  1.0  0.0  0.0
x5   10.0  1.0 -1.0  2.0  0.0  1.0  0.0
x6   20.0  1.0  1.0 -1.0  0.0  0.0  1.0
第 2 个单纯性表是:
        b   x1   x2   x3   x4   x5   x6
obj -20.0  0.0  1.0 -3.0  0.0 -2.0  0.0
x4   30.0  0.0  4.0 -5.0  1.0 -3.0  0.0
x1   10.0  1.0 -1.0  2.0  0.0  1.0  0.0
x6   10.0  0.0  2.0 -3.0  0.0 -1.0  1.0
最终的最优单纯形表是:
        b   x1   x2   x3   x4   x5   x6
obj -25.0  0.0  0.0 -1.5  0.0 -1.5 -0.5
x4   10.0  0.0  0.0  1.0  1.0 -1.0 -2.0
x1   15.0  1.0  0.0  0.5  0.0  0.5  0.5
x2    5.0  0.0  1.0 -1.5  0.0 -0.5  0.5
目标函数的值: 25.0
最优决策变量是:
x1 = 15.0
x2 = 5.0
x3 = 0

总结

单纯形法是线性规划问题中的一种经典算法,它通过逐步优化,找到能够最大化或最小化目标函数的可行解。尽管单纯形法在最坏情况下可能需要指数级时间,但在实际应用中,单纯形法通常能高效地找到最优解,因此它被广泛应用于各种线性规划问题中,例如生产计划、资源分配、运输优化等。
单纯形法的直观性在于从一个顶点开始沿边界移动到另一个顶点,不断提高目标函数值,直到达到最优解。这种方法简单且易于理解,对大多数线性规划问题都能有效求解。然而,单纯形法也存在一些局限性,例如在处理退化问题时可能会出现循环,导致算法陷入无限循环的困境。为了克服这些局限性,研究者们提出了多种改进方案,如反周期规则来防止循环、对偶单纯形法来处理不可行的初始解等。此外,内点法作为一种替代算法,通过从可行域的内部逼近最优解,提供了不同于单纯形法的求解思路,并且在某些情况下表现出更好的最坏情况性能。通过这些改进和新方法的引入,线性规划问题的求解在理论和实践上都得到了极大的丰富和发展,使得我们能够解决更复杂、更大规模的问题。这些进步不仅提升了算法的效率,也拓展了线性规划在各个领域的应用范围。单纯形法及其改进方法的持续发展,确保了线性规划在优化和决策问题中的核心地位。

参考文献

  1. 线性规划-单纯形法推导
  2. python最优化算法实战---线性规划之单纯形法
posted @   郝hai  阅读(1083)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示