线性规划的单纯形法及python实现

1. 线性规划的解

一个线性规划(LP)问题如果有最优解,必定有一个最优解出现在顶点上。

从几何上讲,线性规划的约束集合为凸面体,一个超平面(目标函数的等值面)靠近约束集合时,最先接触到的必然是凸面体的一个顶点或一条边,因此一定有一个最优解出现在顶点上。

2. 线性规划的标准型

线性规划的标准型为:
min ⁡   c T x s . t .   A x = b   x ≥ 0 \begin{align*} \min &~\mathbf{c}^T\mathbf{x}\\ s.t. &~\mathbf{Ax=b}\\ &~\mathbf{x\geq 0} \end{align*} mins.t. cTx Ax=b x0
可以通过以下两个方式转化成标准型:

  1. 将所有不等式约束转化为等式约束:通过增加非负的松弛变量,
  2. 将所有变量转化为非负约束:负约束变量通过引入非负变量,无约束变量使用两个非负变量的差值表示。

对于线性方程组 A x = b \mathbf{Ax=b} Ax=b A ∈ R m × n \mathbf{A}\in\mathbb{R}^{m\times n} ARm×n,通过令 n − m n-m nm个变量为0(非基变量),解出的变量称为基变量,构成一组基本解

3. 初级单纯形法

单纯形法就是在顶点上搜索LP的最优解。求解步骤如下:

  1. 初始化:化成标准型,写出单纯形表,并找一个初始基本解。
    例如(见《运筹学(原书第2版)》(——罗纳德L.拉丁)5.3节):考虑如下标准型:
    max ⁡   12 x 1 + 9 x 2 s . t .   x 1 + x 3   = 1000   x 2 + x 4 = 1500 x 1 + x 2 + x 5 = 1750   4 x 1 + 2 x 2 + x 6 = 4800 x 1 , x 2 , x 3 , x 4 , x 5 , x 6 ≥ 0 \begin{align*} \max ~&12x_1+9x_2\\ s.t. ~&\quad x_1+\quad\quad\quad x_3\quad\quad\quad\quad\quad\quad~=1000\\ &\quad\quad\quad ~x_2+\quad\quad\quad x_4\quad\quad\quad\quad=1500\\ &\quad x_1+x_2+\quad\quad\quad\quad \quad x_5\quad\quad=1750\\ ~&4x_1+2x_2+\quad\quad\quad\quad \quad\quad\quad x_6=4800\\ &x_1,x_2,x_3,x_4,x_5,x_6\geq 0 \end{align*} max s.t.  12x1+9x2x1+x3 =1000 x2+x4=1500x1+x2+x5=17504x1+2x2+x6=4800x1,x2,x3,x4,x5,x60
    先找到一个顶点,即初始基本解。令 x 1 , x 2 = 0 x_1,x_2=0 x1,x2=0为非基变量,可以求解方程组得到初始基本解 x ( 0 ) = ( 0 , 0 , 1000 , 1500 , 1750 , 4800 ) \mathbf{x}^{(0)}=(0,0,1000,1500,1750,4800) x(0)=(0,0,1000,1500,1750,4800)。系数表如下:
x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
c \mathbf{c} c1290000 b \mathbf{b} b
A \mathbf{A} A1010001000
0101001500
1100101750
4200014800
N N N N N N B B B B B B B B B B B B
x ( 0 ) \mathbf{x}^{(0)} x(0)001000150017504800
  1. 找到可行方向 Δ x \Delta \mathbf{x} Δx

首先因为相邻顶点的紧约束组只相差一个,并且标准型只有等式约束,而等式约束始终是紧约束,所以这里能放松的只有非基变量的非负约束。我们可以有 ( Δ x 1 , Δ x 2 ) = ( 1 , 0 ) , ( 0 , 1 ) (\Delta x_1,\Delta x_2)=(1,0),(0,1) (Δx1,Δx2)=(1,0),(0,1)两种选择。

接着根据线性规划的可行方向的性质可知,可行方向满足 A Δ x = 0 \mathbf{A}\Delta\mathbf{x}=\mathbf{0} AΔx=0,将上面两种情况分别代入,可以求解一个线性方程算出基变量的方向。

然后由 Δ f = c T Δ x \Delta f=\mathbf{c}^T\Delta \mathbf{x} Δf=cTΔx可以算出每个方向对函数值的优化情况。

x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
c \mathbf{c} c1290000 b \mathbf{b} b
A \mathbf{A} A1010001000
0101001500
1100101750
4200014800
N N N N N N B B B B B B B B B B B B
x ( 0 ) \mathbf{x}^{(0)} x(0)001000150017504800 c T x = 0 \mathbf{c}^T\mathbf{x}=0 cTx=0
x 1 x_1 x1 Δ x \Delta \mathbf{x} Δx10-10-1-4 Δ f = 12 > 0 \Delta f=12>0 Δf=12>0
x 2 x_2 x2 Δ x \Delta \mathbf{x} Δx010-1-1-2 Δ f = 9 > 0 \Delta f=9>0 Δf=9>0
  1. 判断最优性
    根据每个方向的 Δ f \Delta f Δf可知函数值还可以继续优化,不能优化则迭代停止。
  2. 确定步长
    根据可行方向有负值,可知约束集在此处有界。如果找到一个可以无限移动的方向,说明约束集无界,停止迭代。
    这里取 x 1 x_1 x1 Δ x \Delta \mathbf{x} Δx作为迭代方向。现在让 x ( 0 ) \mathbf{x}^{(0)} x(0)点沿着可行方向移动,直到有一个基变量最先降为0,因此步长为 λ = 1000 \lambda=1000 λ=1000
  3. 新顶点和基
    新顶点为 x ( 1 ) = x ( 0 ) + λ Δ x = ( 0 , 0 , 1000 , 1500 , 1750 , 4800 ) + 1000 × ( 1 , 0 , − 1 , 0 , − 1 , − 4 ) = ( 1000 , 0 , 0 , 1500 , 750 , 800 ) \begin{align*} \mathbf{x}^{(1)}&=\mathbf{x}^{(0)}+\lambda \Delta \mathbf{x}\\ &=(0,0,1000,1500,1750,4800)+1000\times(1,0,-1,0,-1,-4)\\ &=(1000,0,0,1500,750,800)\end{align*} x(1)=x(0)+λΔx=(0,0,1000,1500,1750,4800)+1000×(1,0,1,0,1,4)=(1000,0,0,1500,750,800)
    此时, x 1 x_1 x1入基成为新的基变量, x 3 x_3 x3出基成为非基变量,新基为 { x 1 , x 4 , x 5 , x 6 } \{ x_1, x_4, x_5, x_6\} {x1,x4,x5,x6}。回到第二步,继续寻找可行方向,判断是否能继续优化。迭代过程如下:
x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
c \mathbf{c} c1290000 b \mathbf{b} b
A \mathbf{A} A1010001000
0101001500
1100101750
4200014800
t = 0 t=0 t=0 N N N N N N B B B B B B B B B B B B
x ( 0 ) \mathbf{x}^{(0)} x(0)001000150017504800 c T x = 0 \mathbf{c}^T\mathbf{x}=0 cTx=0
x 1 x_1 x1 Δ x \Delta \mathbf{x} Δx10-10-1-4 Δ f = 12 > 0 , λ = 1000 \Delta f=12>0, \lambda=1000 Δf=12>0,λ=1000
x 2 x_2 x2 Δ x \Delta \mathbf{x} Δx010-1-1-2 Δ f = 9 > 0 \Delta f=9>0 Δf=9>0
t = 1 t=1 t=1 B B B N N N N N N B B B B B B B B B
x ( 1 ) \mathbf{x}^{(1)} x(1)1000001500750800 c T x = 12000 \mathbf{c}^T\mathbf{x}=12000 cTx=12000
x 2 x_2 x2 Δ x \Delta \mathbf{x} Δx010-1-1-2 Δ f = 9 > 0 , λ = 400 \Delta f=9>0, \lambda=400 Δf=9>0,λ=400
x 3 x_3 x3 Δ x \Delta \mathbf{x} Δx-101004 Δ f = − 12 < 0 \Delta f=-12<0 Δf=12<0
t = 2 t=2 t=2 B B B B B B N N N B B B B B B N N N
x ( 2 ) \mathbf{x}^{(2)} x(2)1000400011003500 c T x = 15600 \mathbf{c}^T\mathbf{x}=15600 cTx=15600
x 3 x_3 x3 Δ x \Delta \mathbf{x} Δx-121-2-10 Δ f = 6 > 0 , λ = 350 \Delta f=6>0, \lambda=350 Δf=6>0,λ=350
x 6 x_6 x6 Δ x \Delta \mathbf{x} Δx0-0.500.50.51 Δ f = − 4.5 < 0 \Delta f=-4.5<0 Δf=4.5<0
t = 3 t=3 t=3 B B B B B B B B B B B B N N N N N N
x ( 3 ) \mathbf{x}^{(3)} x(3)650110035040000 c T x = 17700 \mathbf{c}^T\mathbf{x}=17700 cTx=17700
x 5 x_5 x5 Δ x \Delta \mathbf{x} Δx1-2-1210 Δ f = − 6 < 0 \Delta f=-6<0 Δf=6<0
x 6 x_6 x6 Δ x \Delta \mathbf{x} Δx-0.50.50.5-0.501 Δ f = − 1.5 < 0 \Delta f=-1.5<0 Δf=1.5<0

因此最优解为 x ∗ = ( 650 , 1100 , 350 , 400 , 0 , 0 ) \mathbf{x}^*=(650 , 1100 , 350 , 400 , 0 , 0) x=(650,1100,350,400,0,0)

单纯形法只在两种情况下停止迭代:一是证明该标准型可行域无界,二是找到全局最优解。

4. 修正单纯形法

由于在单纯形法中每次迭代都要求解方程组,为了计算高效,使用矩阵运算进行求解。将基变量的系数列向量组合成矩阵 B \mathbf{B} B,那么基向量可以通过 B − 1 b \mathbf{B}^{-1}\mathbf{b} B1b得到,单纯形方向通过 − B − 1 a ( j ) -\mathbf{B}^{-1}a^{(j)} B1a(j)得到,其中 a ( j ) a^{(j)} a(j)是非基变量 x j x_j xj的系数列向量。

换基之后,矩阵 B \mathbf{B} B的某一列被新基的系数列向量所替代,为了快速计算逆矩阵,新基的逆矩阵可以由旧的逆矩阵变换得到: B t + 1 − 1 = E B t − 1 \mathbf{B}^{-1}_{t+1}=\mathbf{EB}^{-1}_{t} Bt+11=EBt1,其中枢轴(pivot)矩阵
E = [ 1 0 ⋯ 0 − Δ x 1 s t Δ x l e a v e 0 ⋯ 0 0 1 ⋯ 0 − Δ x 2 n d Δ x l e a v e 0 ⋯ 0 ⋮ ⋮ ⋱ ⋮ ⋮ ⋮ ⋮ 0 0 ⋯ 1 − Δ x j t h Δ x l e a v e 0 ⋯ 0 0 0 ⋯ 0 − 1 Δ x l e a v e 0 ⋯ 0 0 0 ⋯ 0 ⋮ 0 ⋱ 0 0 0 ⋯ 0 − Δ x m t h Δ x l e a v e 0 ⋯ 1 ] \mathbf{E}=\begin{bmatrix} 1 &0 & \cdots & 0 &-\frac{\Delta x_{1st}}{\Delta x_{leave}} & 0 & \cdots & 0 \\ 0 & 1 & \cdots & 0 &-\frac{\Delta x_{2nd}}{\Delta x_{leave}} & 0 & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots & \vdots & \vdots & & \vdots \\ 0 & 0 & \cdots & 1 &-\frac{\Delta x_{jth}}{\Delta x_{leave}} & 0 & \cdots & 0\\ 0 & 0 & \cdots & 0 & -\frac{1}{\Delta x_{leave}} & 0 & \cdots & 0\\ 0 & 0 & \cdots & 0 & \vdots & 0& \ddots & 0 \\ 0 & 0 & \cdots & 0 & -\frac{\Delta x_{mth}}{\Delta x_{leave}} & 0 & \cdots & 1 \\ \end{bmatrix} E= 100000010000001000ΔxleaveΔx1stΔxleaveΔx2ndΔxleaveΔxjthΔxleave1ΔxleaveΔxmth000000000001
是一个类似于单位阵的矩阵,区别在于出基的那一列被一个列向量替换,分母 Δ x l e a v e \Delta x_{leave} Δxleave是单纯形方向中出基变量对应的值,分子 Δ x j t h \Delta x_{jth} Δxjth是单纯形方向中基变量 j j j对应的元素,从上到下依次排列,主对角线上的元素为 − 1 / Δ x l e a v e -1/\Delta x_{leave} 1/Δxleave

有了逆矩阵之后,可以直接算出目标的变化量:
Δ f = c T Δ x = c j + ( c 1 s t , … , c m t h ) Δ x B = c j − ( c 1 s t , … , c m t h ) B − 1 a ( j ) ≜ c j − v a ( j ) \begin{align}\Delta f&=\mathbf{c}^T\Delta\mathbf{x}=c_j+(c_{1st},\dots,c_{mth})\Delta\mathbf{x}^B\\ &=c_j-(c_{1st},\dots,c_{mth})\mathbf{B}^{-1}a^{(j)}\\ &\triangleq c_j-\mathbf{v}a^{(j)} \end{align} Δf=cTΔx=cj+(c1st,,cmth)ΔxB=cj(c1st,,cmth)B1a(j)cjva(j)
,其中 Δ x B \Delta\mathbf{x}^B ΔxB表示现有基的方向,倒数第二个等式使用了前文公式, v ≜ ( c 1 s t , … , c m t h ) B − 1 \mathbf{v}\triangleq (c_{1st},\dots,c_{mth})\mathbf{B}^{-1} v(c1st,,cmth)B1称为定价向量。因此,无需计算出单纯形方向就可以得到目标值的变化情况。

修正单纯形法的步骤:

  1. 初始化。找到一组初始可行基,使用其系数矩阵 B \mathbf{B} B求解方程组 B x B = b \mathbf{Bx}^B=\mathbf{b} BxB=b得到一组初始可行解 x ( 0 ) \mathbf{x}^{(0)} x(0),其中非基变量都是0。
    例如:同样是第3节的例子,选择 ( x 3 , x 4 , x 5 , x 6 ) (x_3,x_4,x_5,x_6) (x3,x4,x5,x6)为初始基,则系数矩阵如下:
x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
c \mathbf{c} c1290000 b \mathbf{b} b
A \mathbf{A} A1010001000
0101001500
1100101750
4200014800
N N N N N N B B B B B B B B B B B B
x ( 0 ) \mathbf{x}^{(0)} x(0)001000150017504800

B t = 0 − 1 = [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ] \mathbf{B}^{-1}_{t=0}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ 0 & 0 & 1 & 0\\ 0 & 0& 0& 1\\ \end{bmatrix} Bt=01= 1000010000100001
3. 定价。使用系数矩阵求出定价向量 v = ( c B ) T B − 1 \mathbf{v}=(\mathbf{c}^{B})^T\mathbf{B}^{-1} v=(cB)TB1,其中 c B \mathbf{c}^{B} cB是基变量在目标函数中的系数向量。然后分别令每一个非基变量 x j = 1 x_j=1 xj=1,使用公式(3)可以求出每个非基变量的目标函数变化量。
v = [ 0 0 0 0 ] , when  x 1 = 1 , Δ f = c 1 = 12 , when  x 2 = 1 , Δ f = c 1 = 9 \begin{align*}&\mathbf{v}=\begin{bmatrix} 0 & 0 & 0 & 0 \end{bmatrix},\\ &\text{when } x_1=1, \Delta f=c_1=12, \\ &\text{when } x_2=1, \Delta f=c_1=9 \end{align*} v=[0000],when x1=1,Δf=c1=12,when x2=1,Δf=c1=9
5. 判断最优解。如果没有一个方向可以继续优化目标函数,则停止迭代,否则选择一个非基变量入基。(注意此时无法判断哪个变量出基,需要在下一步计算单纯形方向后才能决定)

根据 Δ f \Delta f Δf可知 x 1 , x 2 = 1 x_1,x_2=1 x1,x2=1都能优化目标值,取 x 1 = 1 x_1=1 x1=1

  1. 单纯形方向 Δ x B = − B − 1 a ( j ) \Delta\mathbf{x}^B=-\mathbf{B}^{-1}a^{(j)} ΔxB=B1a(j) a ( j ) a^{(j)} a(j)是上一步选择入基的变量的系数向量。
    Δ x B = − B − 1 a ( 1 ) = − [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ] [ 1 0 1 4 ] = [ − 1 − 0 − 1 − 4 ] \Delta\mathbf{x}^B = -\mathbf{B}^{-1}a^{(1)}=-\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ 0 & 0 & 1 & 0\\ 0 & 0& 0& 1\\ \end{bmatrix}\begin{bmatrix} 1\\ 0 \\ 1\\ 4 \\ \end{bmatrix}=\begin{bmatrix} -1\\ -0 \\ -1\\ -4 \\ \end{bmatrix} ΔxB=B1a(1)= 1000010000100001 1014 = 1014
  2. 步长。如果单纯形方向所有元素都非负,则停止计算,约束无界。否则选择最先降为0的基变量出基,相应的移动距离为步长。

λ = 1000 \lambda = 1000 λ=1000

  1. 新基和新顶点。新顶点为 x ( t + 1 ) = x ( t ) + λ Δ x \mathbf{x}^{(t+1)}=\mathbf{x}^{(t)}+\lambda\Delta\mathbf{x} x(t+1)=x(t)+λΔx,构造枢轴矩阵 E \mathbf{E} E,并更新系数矩阵的逆矩阵为 E B − 1 \mathbf{EB}^{-1} EB1。重复步骤2。

根据单纯形方向可知 x 3 x_3 x3出基,因此
E = [ − 1 − 1 0 0 0 0 1 0 0 − − 1 − 1 0 1 0 − − 4 − 1 0 0 1 ] = [ 1 0 0 0 0 1 0 0 − 1 0 1 0 − 4 0 0 1 ] , B t = 1 − 1 = E B t = 0 − 1 = [ 1 0 0 0 0 1 0 0 − 1 0 1 0 − 4 0 0 1 ] \mathbf{E}=\begin{bmatrix} -\frac{1}{-1} & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -\frac{-1}{-1} & 0 & 1 & 0\\ -\frac{-4}{-1} & 0& 0& 1\\ \end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -1 & 0 & 1 & 0\\ -4 & 0& 0& 1\\ \end{bmatrix},\mathbf{B}^{-1}_{t=1}=\mathbf{E}\mathbf{B}^{-1}_{t=0}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -1 & 0 & 1 & 0\\ -4 & 0& 0& 1\\ \end{bmatrix} E= 1101114010000100001 = 1014010000100001 ,Bt=11=EBt=01= 1014010000100001

迭代过程如下:

x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
c \mathbf{c} c1290000 b \mathbf{b} b
A \mathbf{A} A1010001000
0101001500
1100101750
4200014800
t = 0 t=0 t=0 N N N N N N 1 s t 1st 1st 2 n d 2nd 2nd 3 r d 3rd 3rd 4 t h 4th 4th
x ( 0 ) \mathbf{x}^{(0)} x(0)001000150017504800

B t = 0 − 1 = [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 ] , v T = [ 0 0 0 0 ] \mathbf{B}^{-1}_{t=0}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ 0 & 0 & 1 & 0\\ 0 & 0& 0& 1\\ \end{bmatrix}, \mathbf{v}^T=\begin{bmatrix} 0 \\ 0\\ 0\\ 0 \end{bmatrix} Bt=01= 1000010000100001 ,vT= 0000

x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
Δ f \Delta f Δf1290000
x 1 x_1 x1 Δ x \Delta \mathbf{x} Δx10-10-1-4 λ = 1000 \lambda=1000 λ=1000
t = 1 t=1 t=1 1 s t 1st 1st N N N N N N 2 n d 2nd 2nd 3 r d 3rd 3rd 4 t h 4th 4th
x ( 1 ) \mathbf{x}^{(1)} x(1)1000001500750800 c T x = 12000 \mathbf{c}^T\mathbf{x}=12000 cTx=12000

E = [ − 1 − 1 0 0 0 0 1 0 0 − − 1 − 1 0 1 0 − − 4 − 1 0 0 1 ] = [ 1 0 0 0 0 1 0 0 − 1 0 1 0 − 4 0 0 1 ] , B t = 1 − 1 = E B t = 0 − 1 = [ 1 0 0 0 0 1 0 0 − 1 0 1 0 − 4 0 0 1 ] , v T = [ 12 0 0 0 ] \mathbf{E}=\begin{bmatrix} -\frac{1}{-1} & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -\frac{-1}{-1} & 0 & 1 & 0\\ -\frac{-4}{-1} & 0& 0& 1\\ \end{bmatrix}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -1 & 0 & 1 & 0\\ -4 & 0& 0& 1\\ \end{bmatrix},\mathbf{B}^{-1}_{t=1}=\mathbf{E}\mathbf{B}^{-1}_{t=0}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& 0\\ -1 & 0 & 1 & 0\\ -4 & 0& 0& 1\\ \end{bmatrix},\mathbf{v}^T=\begin{bmatrix} 12 \\ 0\\ 0\\ 0 \end{bmatrix} E= 1101114010000100001 = 1014010000100001 ,Bt=11=EBt=01= 1014010000100001 ,vT= 12000

x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
Δ f \Delta f Δf09-12000
x 2 x_2 x2 Δ x \Delta \mathbf{x} Δx010-1-1-2 λ = 400 \lambda=400 λ=400
t = 2 t=2 t=2 1 s t 1st 1st 4 t h 4th 4th N N N 2 n d 2nd 2nd 3 r d 3rd 3rd N N N
x ( 2 ) \mathbf{x}^{(2)} x(2)1000400011003500 c T x = 15600 \mathbf{c}^T\mathbf{x}=15600 cTx=15600

E = [ 1 0 0 0 0 1 0 − 0.5 0 0 1 − 0.5 0 0 0 0.5 ] , B t = 2 − 1 = E B t = 1 − 1 = [ 1 0 0 0 2 1 0 − 0.5 1 0 1 − 0.5 − 2 0 0 0.5 ] , v T = [ 12 0 0 9 ] B t = 2 − 1 = [ − 6 0 0 4.5 ] \begin{align*}&\mathbf{E}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1& 0& -0.5\\ 0 & 0 & 1 & -0.5\\ 0 & 0& 0& 0.5\\ \end{bmatrix},\mathbf{B}^{-1}_{t=2}=\mathbf{E}\mathbf{B}^{-1}_{t=1}=\begin{bmatrix} 1 & 0 & 0 & 0\\ 2 & 1& 0& -0.5\\ 1 & 0 & 1 & -0.5\\ -2 & 0& 0& 0.5\\ \end{bmatrix},\\ &\mathbf{v}^T=\begin{bmatrix} 12&0&0&9 \end{bmatrix}\mathbf{B}^{-1}_{t=2}=\begin{bmatrix} -6 \\ 0\\ 0\\ 4.5 \end{bmatrix}\end{align*} E= 10000100001000.50.50.5 ,Bt=21=EBt=11= 12120100001000.50.50.5 ,vT=[12009]Bt=21= 6004.5

x 1 x_1 x1 x 2 x_2 x2 x 3 x_3 x3 x 4 x_4 x4 x 5 x_5 x5 x 6 x_6 x6
Δ f \Delta f Δf00600-4.5
x 3 x_3 x3 Δ x \Delta \mathbf{x} Δx-121-2-10 λ = 350 \lambda=350 λ=350
t = 3 t=3 t=3 1 s t 1st 1st 4 t h 4th 4th 3 r d 3rd 3rd 2 n d 2nd 2nd N N N N N N
x ( 3 ) \mathbf{x}^{(3)} x(3)650110035040000 c T x = 17700 \mathbf{c}^T\mathbf{x}=17700 cTx=17700

E = [ 1 0 − 1 0 0 1 − 2 0 0 0 − 1 0 0 0 2 1 ] , B t = 3 − 1 = E B t = 2 − 1 = [ 0 0 − 1 0.5 0 1 − 2 0.5 1 0 1 − 0.5 0 0 2 − 0.5 ] , v T = [ 12 0 0 9 ] B t = 3 − 1 = [ 0 0 6 1.5 ] \begin{align*}&\mathbf{E}=\begin{bmatrix} 1 & 0 & -1 & 0\\ 0 & 1& -2& 0\\ 0 & 0 & -1 & 0\\ 0 & 0& 2& 1\\ \end{bmatrix},\mathbf{B}^{-1}_{t=3}=\mathbf{E}\mathbf{B}^{-1}_{t=2}=\begin{bmatrix} 0 & 0 & -1 & 0.5\\ 0 & 1& -2 & 0.5\\ 1 & 0 & 1 & -0.5\\ 0 & 0& 2& -0.5\\ \end{bmatrix},\\ &\mathbf{v}^T=\begin{bmatrix} 12&0&0&9 \end{bmatrix}\mathbf{B}^{-1}_{t=3}=\begin{bmatrix} 0 \\ 0\\ 6\\ 1.5 \end{bmatrix}\end{align*} E= 1000010012120001 ,Bt=31=EBt=21= 0010010012120.50.50.50.5 ,vT=[12009]Bt=31= 0061.5

Δ f \Delta f Δf0000-6-1.5最优

5. 修正单纯形的代码实现

import numpy as np
import pandas as pd
import copy

class Simplex:
    def __init__(self,A, b, c):
        columns=["b"]
        for i in range(A.shape[1]):
            columns.append("x"+str(i+1))
        index = ["c"] + columns[A.shape[1]-A.shape[0]+1:]

        b = np.asmatrix(b)
        matrix = np.concatenate((b.T, A), axis=1)
        c = np.asmatrix(np.append(0, c))
        matrix = np.concatenate((c, matrix), axis=0)
        matrix = pd.DataFrame(matrix,index=index, columns=columns)
        self.matrix = copy.deepcopy(matrix)
        # 基变量
        self.basic_varible = self.matrix.iloc[1:,0].index.tolist()
        self.basic_varible_len = len(self.basic_varible)
        # 非基变量
        self.nonbasic_varible = list(set(self.matrix.columns.tolist()[1:])-set(self.basic_varible))
        self.nonbasic_varible_len = len(self.nonbasic_varible)
        # 对目标函数的优化量
        self.reduce_cost = self.matrix.iloc[0][self.nonbasic_varible] 
        print(matrix)

    def solve(self):
        iteration = 1
        B = self.matrix.loc[self.basic_varible,self.basic_varible]
        c = copy.deepcopy(self.matrix.iloc[0,1:])
        while self.reduce_cost.min() < -1e-5:
            print(f"第{iteration}次迭代")
            #出基,进基
            #选择对函数值改进量最大的非基变量xj
            print("目标改进量:\n", self.reduce_cost)
            basic_in = self.reduce_cost.idxmin()
            #非基变量xj的系数aj
            aj = self.matrix.iloc[1:][basic_in]
            deltax = -B.dot(aj) # 单纯形方向
            print("单纯形方向:\n", deltax)

            if deltax.min() > 0:
                print("无界")
                return 

            xB = self.matrix.iloc[1:,0] # 基变量的值
            if xB.min() < 0:
                print("无解")
                return
            
            # 选出基变量
            step = (-xB/deltax).replace([np.inf, -np.inf], np.nan)
            step = step[step>0]
            # print("每个基变量的步长:\n", step)
            lambda_ = step.min()
            basic_out = step.idxmin()
            print(f"进基: {basic_in}",f"出基: {basic_out}")

            self.basic_varible[self.basic_varible.index(basic_out)] = basic_in
            self.nonbasic_varible[self.nonbasic_varible.index(basic_in)] = basic_out

            # 枢轴矩阵
            E = pd.DataFrame(np.eye(self.basic_varible_len), index=B.index,columns=B.columns)
            E.loc[:, basic_out] = -deltax/deltax.loc[basic_out]
            E.loc[basic_out,basic_out] = -1/deltax.loc[basic_out]
            B = E.dot(B)
            print("枢轴矩阵:\n", E)
            
            B.index = self.basic_varible
            B.columns = self.basic_varible
            print("系数矩阵:\n", B)

            cB = c[self.basic_varible]
            v = cB.T.dot(B)
            index1 = self.matrix.iloc[0:,0].index.tolist()
            index1[1:] = self.basic_varible
            self.matrix.index = index1

            self.matrix.iloc[0,0] = 0
            for idx in self.basic_varible:
                if idx == basic_in:
                    self.matrix.loc[idx, self.matrix.columns[0]] = lambda_
                else:
                    self.matrix.loc[idx,self.matrix.columns[0]] += lambda_*deltax.loc[idx]
                self.matrix.iloc[0,0] += self.matrix.loc[idx,:][0] * c[idx]

            for idx in self.matrix.columns[1:]:
                self.matrix.loc[self.matrix.index[0],idx] = c.loc[idx] - v.T.dot(self.matrix.loc[:, idx][1:])
            self.reduce_cost = self.matrix.iloc[0,1:]
            iteration += 1
            print(self.matrix)

        print(f"*********运行完毕,一共迭代{iteration-1}次**************")
        print("******最优解**********")
        for x in self.matrix.columns[1:]:
            if x in self.basic_varible:
                print(f"{x}:",self.matrix.loc[x,"b"],end="\t")
            else:
                print(f"{x}:",0,end="\t")
        print("\nobj:",-self.matrix.iloc[0][0])



A=np.asarray([
    [1, 0, 1, 0, 0 ,0],
    [0, 1, 0, 1, 0, 0],
    [ 1, 1, 0, 0, 1, 0],
    [4, 2, 0, 0, 0, 1]])
b = np.asarray([1000,1500,1750,4800])
c = np.asarray([-12,-9,0,0,0,0])
simplex = Simplex(A,b,c)

simplex.solve()
  • 14
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值