从一维cutting问题看列生成算法

从一维cutting问题看列生成算法

  • 列生成算法
    • 一维cutting问题
    • 列生成原理
    • 集合覆盖模型
    • 列生成步骤说明
    • python 代码实现

列生成算法

列生成在求解大型线性规划时往往都表现良好,在很多时候,一个变量很多的线性规划问题中,往往很多的列是用不到的,或者说,它们并不影响最优解的求解。列生成正是基于这样一种思想,从有限列出发,每次在求解限制问题后,判断是否达到最优,若达到,则返回结果,否则,添加新的列,继续求解,直到求出最优解为止。
本文将从列生成原理的证明,基于一维cutting问题的步骤说明和python代码实现来详细讲解列生成算法。同时比较该问题的几种模型在gurobi求解下的速度和解的质量。

一维cutting问题

一维cutting问题可以描述为:假设有无限多的长度为 L L L的木板和 n n n种类型的需求,第 i i i ( i i i=1,…, n n n)类型需求的尺寸为 l i l_i li,需求数量为 d i d_i di,设 M = { 1 , 2 , . . . , m } M=\{1,2,...,m\} M={1,2,...,m} N = { 1 , 2 , . . . , n } N=\{1,2,...,n\} N={1,2,...,n}试求如何选择下料方式,在满足需求的情况下,使得使用的木板(board)数目最少
在进一步说明列生成之前,我们先看一维cutting问题的相关模型描述比较不同模型求解的效率。

该问题的模型建立是简单的,在建立第一个模型之前,我们先定义相关的决策变量:
y j = 1 y_j=1 yj=1 如果第 j j j个木板被使用,否则 y j = 0 y_j=0 yj=0 y j ∈ { 0 , 1 } y_j \in \{0,1\} yj{0,1};
x i j x_{ij} xij 代表来自第 j j j个木板的第 i i i中类型需求的数量, x i j ∈ N x_{ij}\in\N xijN.

m o d e l model model 1 : 1: 1:
m i n ∑ j ∈ M y j min\sum\limits_{j\in M}y_j minjMyj (1)

s.t. I y j ≥ x i j , i ∈ N , j ∈ M Iy_j\ge x_{ij},i\in N,j\in M Iyjxij,iN,jM (2)

∑ j ∈ M l i x i j ≤ L , j ∈ M \sum\limits_{j\in M}l_ix_{ij}\le L,j\in M jMlixijL,jM (3)

∑ i ∈ N x i j ≥ d i , i ∈ N \sum\limits_{i\in N}x_{ij}\ge d_i, i\in N iNxijdi,iN (4)

公式(1)定义了问题的目标,即使用的board数量最少,显然, I I I是一个充分大的数,且 m = ∑ i ∈ N d i m=\sum\limits_{i\in N}d_i m=iNdi显然是该问题的一个上界。当然, m m m取值越大意味着更多的决策变量,而实际上,任何一种启发式方法或者可行方案下使用的board数目都是该问题的一个可行上界。而在该问题中,我们取简单上界 m = ∑ i ∈ N ⌈ d i ⌊ L l i ⌋ ⌉ m=\sum\limits_{i \in N}{\left\lceil \frac{d_i}{\left\lfloor \frac{L}{l_i} \right\rfloor} \right\rceil} m=iNliLdi。公式(2)限制了当 y j = 0 y_j=0 yj=0时,即第 j j j个board不被使用时, x i j = 0 x_{ij}=0 xij=0。其中, I I I是一个充分大的常数,因此当 y j = 0 y_j=0 yj=0时,对 x i j x_{ij} xij不作约束。公式(3)限制了从board j j j上切下的物品尺寸总和不能超过baord的总长 L L L。公式(4)则表示相应的需求约束。

我们通过一个实例的求解来说明下这个模型的求解效率,我们设 L = 110 L=110 L=110,考虑5种不同的需求如下表所示。

尺寸 l i l_i li 20 45 50 55 75
需求 d i d_i di 48 35 24 10 8

将数据代入模型1,python编程,调用gurobi求解得到的结果为 O P T = 47 OPT=47 OPT=47,时间 r u n t i m e = 30.3 s runtime=30.3s runtime=30.3s.
进一步地,我们用该模型的松弛形式,即松弛 0 ≤ y j ≤ 1 0 \le y_j \le 1 0yj1 x i j ≥ 0 x_{ij} \ge 0 xij0 代替model 1中的决策变量约束来估计该问题的下界。得到 O P T = 0.048 OPT=0.048 OPT=0.048,时间 r u n t i m e = 0.009 s runtime=0.009s runtime=0.009s下界的意义之一在于:随着求解规模的增大,当一个模型的求解时间是呈指数增长时,我们往往会选择一些启发式算法或智能算法来求解相应的问题。因此,此时可以用下界来评价一个算法的有效性(effectiveness),而当你提供一个足够好的下界,而你启发式算法的求解结果和下界差距足够小时,即可以说明你的算法能求解出足够好的近似优解。显然,第一个模型的松弛模型的下界足够差。因为我们可以很简单地得到该问题的一个连续下界
l o w e r b o u n d = ⌈ ∑ i ∈ N d i l i L ⌉ ( 5 ) lowerbound=\left\lceil \frac{\sum\limits_{i \in N}{d_il_i}}{L} \right\rceil (5) lowerbound=LiNdili(5).
且通过公式(5)我们可以求得的该实例的下界为45.

很多时候,模型建立的不同可能会对求解效率产生很大的影响,基于model 1,建立新的cutting模型,如下所示。

m o d e l model model 2 : 2: 2:
m i n ∑ j ∈ M y j min\sum\limits_{j\in M}y_j minjMyj (6)

s.t. ∑ j ∈ M l i x i j ≤ L y j , j ∈ M \sum\limits_{j\in M}l_ix_{ij}\le Ly_j,j\in M jMlixijLyj,jM (7)

∑ i ∈ N x i j ≥ d i , i ∈ N \sum\limits_{i\in N}x_{ij}\ge d_i, i\in N iNxijdi,iN (8)

该模型进行了简单的调整,经过求解器求解,我们可以得到 O P T = 47 OPT=47 OPT=47,时间 r u n t i m e = 8 s runtime=8s runtime=8s. 而对应的松弛模型 r u n t i m e = 0.003 s , O P T = 44.41 runtime=0.003s,OPT=44.41 runtime=0.003sOPT=44.41。实际上,我们可以发现,该线性模型求解得结果和公式(5)求解结果是相同的,在其对应的松弛问题中,我们可以定义 y j y_j yj为board j j j 使用的比例 0 ≤ y j ≤ 1 0 \le y_j \le 1 0yj1,从这个角度上来看,它和公式(5)的原理是一致的。

同时,从这里我们可以看出,建立不同的数学模型,可能会极大地影响模型的求解效率。

列生成原理

首先考虑一个目标为极小值的线性规划模型 P P P 如下所示

min z = c T x z=c^Tx z=cTx
( P ) (P) (P) { A x ≥ b x ≥ 0 ( 9 ) \left\{ \begin{array}{l} Ax \ge b \\ x \ge 0 \end{array} \right. (9) {Axbx0(9)

其中, A A A m × n m \times n m×n的二维矩阵, c , x c,x c,x 均为 n × 1 n \times 1 n×1的列向量, b b b m × 1 m \times 1 m×1的列向量。设 A ~ \tilde A A~ m × n ′ m \times n' m×n的二维矩阵,且 n ′ ≤ n n' \le n nn A ~ \tilde A A~中列向量为 A A A中列向量的子集,则我们可以定义相应的限制问题 R P RP RP如下所示

min z = c ′ T x ′ z=c'^Tx' z=cTx
( R P ) (RP) (RP) { A ~ x ′ ≥ b x ′ ≥ 0 ( 10 ) \left\{ \begin{array}{l} \tilde Ax' \ge b \\ x' \ge 0 \end{array} \right. (10) {A~xbx0(10)

模型 ( P ) (P) (P)和模型 ( R P ) (RP) (RP)的对偶问题 D P DP DP D R P DRP DRP可以表示如下:

max w = y T b w=y^Tb w=yTb
( D P ) (DP) (DP) { A T y ≤ c y ≥ 0 ( 11 ) \left\{ \begin{array}{l} A^Ty \le c \\ y \ge 0 \end{array} \right. (11) {ATycy0(11)

max w = y T b w=y^Tb w=yTb
( D R P ) (DRP) (DRP) { A ~ T y ≤ c ′ y ≥ 0 ( 12 ) \left\{ \begin{array}{l} \tilde A^Ty \le c' \\ y \ge 0 \end{array} \right. (12) {A~Tycy0(12)

由强对偶性可知,如果 ( R P ) (RP) (RP)的最优解是 P P P的最优解,当且仅当 D R P DRP DRP的最优解是 D P DP DP的最优解。此时,由于 D R P DRP DRP的行(即约束)是 R P RP RP的行的子集,从另一方面理解, R P RP RP问题的解空间是 D R P DRP DRP的解空间的子集。因此,若 D R P DRP DRP问题的最优解满足 D P DP DP的所有约束,则 D R P DRP DRP的最优解即为 R P RP RP问题的最优解。

综上所述,当求出 R P RP RP的最优解 x ′ ∗ x'^* x时,要判断其是否是 P P P的最优解 x ∗ x^* x,则需要判断 D R P DRP DRP模型最优解 y ∗ y^* y是否满足 D P DP DP中的所有约束。设 a i a_i ai为系数矩阵 A A A中的列向量,则模型 D P DP DP可以重新写为:

max w = y T b w=y^Tb w=yTb
( D P ) (DP) (DP) { a i T y ≤ c i , i = 1 , 2 , . . . , n y ≥ 0 ( 13 ) \left\{ \begin{array}{l} a_i^Ty \le c_i,i=1,2,...,n \\ y \ge 0 \end{array} \right. (13) {aiTyci,i=1,2,...,ny0(13)

因此,若 y ∗ y^* y D P DP DP的最优解,即满足 D P DP DP的所有约束,则应该 a i T y ∗ ≤ c i , ∀ i = 1 , 2 , . . . , n a_i^Ty^* \le c_i,\forall i=1,2,...,n aiTyci,i=1,2,...,n。判断 y ∗ y^* y是否满足 ( 13 ) (13) (13)中的所有约束,等价于求解 ( 14 ) (14) (14)

( 14 ) (14) (14)
min z = c i − a i T y ∗ z=c_i-a_i^Ty^* z=ciaiTy
a i ∈ A a_i \in A aiA

如果我们求解该问题 w ∗ ≥ 0 w^* \ge 0 w0,即 ∀ i , a i T y ∗ ≤ c i \forall i, a_i^Ty^* \le c_i i,aiTyci,此时 y ∗ y^* y即为 D P DP DP的最优解。若 w ∗ < 0 w^* \lt 0 w<0,则应添加相应的 a i ∗ a_{i^*} ai,继续求解,直到 w ∗ ≥ 0 w^* \ge 0 w0为止。

集合覆盖模型

该部分建立该问题的集合覆盖(set-covering model),如下所示:

min ∑ j ∈ P x j \sum\limits_{j \in P}{x_j} jPxj

{ ∑ j ∈ P n j i x j ≥ d i , i ∈ N x j ∈ N , j ∈ P ( 15 ) \left\{ \begin{array}{l} \sum\limits_{j \in P}n_{ji}x_j \ge d_i,i \in N\\ x_j \in N,j \in P \end{array} \right. (15) {jPnjixjdi,iNxjN,jP(15)

其中, P P P为所有可行的切割方式 ( p a t t e r n ) (pattern) (pattern) n j i n_{ji} nji为pattern j j j中第 i i i中类型需求的数量, x j x_j xj为pattern j j j的使用数目。

但是事实上,实现罗列出来所有可行的pattern 是不可行的,而往往在最优解中使用到的pattern的数量一般是远远小于总的pattern数量的。因此,借鉴列生成的思路,从有限列(即限制问题 R P RP RP)出发,经过不断的迭代,每次判断当前有限列是否达到最优,若达到,返回当前最优解;否则,添加列,直至达到最优为止。其流程图如下所示。

Created with Raphaël 2.2.0 开始 求解RP 求解定价子问题 reduced cost < 0? 添加列至RP 结束 yes no

列生成步骤说明

本部分通过一维cutting问题的实例详细说明该问题的求解步骤。
设初始集合覆盖模型系数矩阵为:

n = [ 5 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 2 0 0 0 0 0 1 ] n = \left[ {\begin{array}{l} 5&0&0&0&0 \\ 0&2&0&0&0 \\ 0&0&2&0&0 \\ 0&0&0&2&0 \\ 0&0&0&0&1 \\ \end{array}} \right] n=5000002000002000002000001

如第1列 n 1 = ( 5 , 0 , 0 , 0 , 0 ) T n_1=(5,0,0,0,0)^T n1=(5,0,0,0,0)T代表的切割方式表示第一种类型需求为5,其余为0,因为 ⌊ L l 1 ⌋ = 5 \left\lfloor \frac{L}{l_1} \right\rfloor = 5 l1L=5,其余列以此类推。

事实上,建立一个这样的初始求解系数矩阵,能保证问题始终存在可行解。

i t e r iter iter 1:求解限制问题 R P RP RP, x ∗ = ( 9.6 , 17.5 , 12 , 5 , 8 ) T x^*=(9.6, 17.5, 12, 5, 8)^T x=(9.6,17.5,12,5,8)T,对应的对偶变量 π = ( 0.2 , 0.5 , 0.5 , 0.5 , 1.0 ) T \pi=(0.2, 0.5, 0.5, 0.5, 1.0)^T π=(0.2,0.5,0.5,0.5,1.0)T,求解定价子问题:

min z = 1 − y T π z=1-y^T\pi z=1yTπ

{ ∑ i ∈ N y i l j ≤ L y i ∈ N \left\{ \begin{array}{l} \sum\limits_{i \in N}y_il_j \le L\\ y_i \in N \end{array} \right. {iNyiljLyiN

y i y_i yi表示在该可行的patern中第 i i i中类型需求的数目,则 y ∗ = ( 1 , 2 , 0 , 0 , 0 ) T y^*=(1,2,0,0,0)^T y=(1,2,0,0,0)T z ∗ = − 0.2 < 0 z^*=-0.2 \lt 0 z=0.2<0,因此添加 ( 1 , 2 , 0 , 0 , 0 ) T (1,2,0,0,0)^T (1,2,0,0,0)T到原问题系数列,继续求解;

i t e r iter iter 2: 求解新的 R P RP RP问题, x ∗ = ( 6.1 , 0 , 12 , 5 , 8 , 17.5 ) T x^*=(6.1, 0,12, 5, 8, 17.5)^T x=(6.1,012,5,817.5)T,对应的对偶变量 π = ( 0.2 , 0.4 , 0.5 , 0.5 , 1.0 ) T \pi=(0.2, 0.4, 0.5, 0.5, 1.0)^T π=(0.2,0.4,0.5,0.5,1.0)T,求解定价子问题, y ∗ = ( 1 , 0 , 0 , 0 , 1 ) T y^*=(1,0,0,0,1)^T y=(1,0,0,0,1)T z ∗ = − 0.2 < 0 z^*=-0.2 \lt 0 z=0.2<0,因此添加 ( 1 , 0 , 0 , 0 , 1 ) T (1,0,0,0,1)^T (1,0,0,0,1)T到原问题系数列,继续求解;

i t e r iter iter 3: 求解新的 R P RP RP问题, x ∗ = ( 4.5 , 0 , 12 , 5 , 0 , 17.5 , 8 ) T x^*=(4.5, 0,12, 5, 0, 17.5, 8)^T x=(4.5,012,5,0,17.5,8)T,对应的对偶变量 π = ( 0.2 , 0.4 , 0.5 , 0.5 , 0.8 ) T \pi=(0.2, 0.4, 0.5, 0.5, 0.8)^T π=(0.2,0.4,0.5,0.5,0.8)T,求解定价子问题, y ∗ = ( 3 , 0 , 1 , 0 , 0 ) T y^*=(3,0,1,0,0)^T y=(3,0,1,0,0)T z ∗ = − 0.1 < 0 z^*=-0.1 \lt 0 z=0.1<0,因此添加 ( 3 , 0 , 1 , 0 , 0 ) T (3,0,1,0,0)^T (3,0,1,0,0)T到原问题系数列,继续求解;

i t e r iter iter 3: 求解新的 R P RP RP问题, x ∗ = ( 0 , 0 , 8.25 , 5 , 0 , 17.5 , 8 , 7.5 ) T x^*=(0, 0, 8.25, 5, 0, 17.5, 8, 7.5)^T x=(0,0,8.25,5,0,17.5,8,7.5)T,对应的定价子问题 z ∗ > 0 z^* \gt 0 z>0,结束循环,输入最优解46.25;

由上述问题可以看到,对列生成求解的下界向上取整,其值和最优解相等。因为,集合覆盖模型往往能获得一个更好的下界,因为一般来说,集合覆盖模型的可行解是原问题的可行解,而原问题的可行解不一定是结合覆盖模型和可行解。

python 代码实现

本博客所有涉及模型实现和列生成算法为python调用gurobi编写,相关代码链接可见 https://github.com/shaoxiang-zheng/operation-algorithm.git

你可能感兴趣的:(一维cutting问题,列生成,gurobi,&amp;,python)