列生成算法及python实践

列生成算法及python实践

列生成算法是在混合整数规划中一个经典的且强大的精确算法。

引例-下料问题

一家木材厂有一种长度为80英寸的木材原料。现在有3个顾客,他们分别需要46个10英寸,22个11英寸,43个19英寸的木材产品。
为了满足客户不同的需求并且使得切割的原料最少,问该公司最少需要的木材多少根,以及如何切割?

为了方便求解该问题,我们引入如下记号:

记号含义
m m m客户的集合
W W W木材的最大宽度
w i , i ∈ m w_i,i\in m wiim客户 i i i要求的棒材宽度
n i , i ∈ m n_i,i\in m niim客户 i i i对棒材宽度为 w i w_i wi的需求数量

求解方法

Kantorovich 建模方式

记号含义
K \mathcal{K} K待切割的棒材的集合
y k ∈ { 0 , 1 } y_k\in\{0,1\} yk{0,1}棒材 k k k是否被切割,1表示切割,0表示不切割
x i k x_i^k xik棒材 k k k被规格为 w i w_i wi切割的个数

于是可以将数学模型表述为如下形式:
min ∑ k ∈ K y k s.t. ∑ k ∈ K x i k ≥ n i , i = 1 , … , m , (demand) ∑ i = 1 n w i x i k ≤ W y k , k ∈ K , (width limitation) x i k ∈ Z + , y k ∈ { 0 , 1 } . \begin{aligned} &\text{min} \sum_{k\in\mathcal{K}}y_k \\ &\text{s.t.} \sum_{k\in\mathcal{K}}x_i^k\geq n_i,\quad i=1,\ldots,m,\quad\text{(demand)} \\ &\sum_{i=1}^nw_ix_i^k\leq Wy_k,\quad k\in\mathcal{K},\quad\text{(width limitation)} \\ &x_i^k\in\mathbb{Z}_+, y_k\in\{0,1\}. \end{aligned} minkKyks.t.kKxikni,i=1,,m,(demand)i=1nwixikWyk,kK,(width limitation)xikZ+,yk{0,1}.

缺点
  • 线性松弛界质量太差,当问题规模大时需要构造大量的二进制变量和整数变量。

列生成算法

列生成的建模方式与Kantorovich建模方式不同,需要引入pattern的概念,即对于一根木材原料切割方案,比如一根80英寸的原料可以切割成8个10英寸的产品。下表给出了一些pattern:

10英寸11英寸19英寸浪费的木材长度切割的次数
pattern18000 x 1 x_1 x1
pattern26109 x 2 x_2 x2
pattern36011 x 3 x_3 x3
pattern45110 x 4 x_4 x4
客户的需求4622430

pattern的数量会随着需求产品种类的增加而指数级增加,针对上表中的pattern,我们给出4种切割方案的模型:
min  ∑ i = 1 4 1 ∗ x i s.t.  8 x 1 + 6 x 2 + 6 x 3 + 5 x 4 ≥ 46   0 x 1 + 1 x 2 + 0 x 3 + 1 x 4 ≥ 22 0 x 1 + 0 x 2 + 1 x 3 + 0 x 4 ≥ 43 x 1 , x 2 , x 3 , x 4 ∈ Z + \begin{aligned} \text{min}~&\sum_{i=1}^41*x_i \\ \text{s.t.}~&8x_1+6x_2+6x_3+5x_4\geq46\ \\ &0x_1+1x_2+0x_3+1x_4\geq22\\ &0x_1+0x_2+1x_3+0x_4\geq43\\ &x_1,x_2,x_3,x_4\in\mathbb{Z}_+\\ \end{aligned} min s.t. i=141xi8x1+6x2+6x3+5x446 0x1+1x2+0x3+1x4220x1+0x2+1x3+0x443x1,x2,x3,x4Z+
其实上述的模型并没有把pattern给枚举完全,也即模型的列不完全,所以被称为限制性主问题(restrictive master problem)。单纯形法的经验告诉我们求解像上述的3行的优化问题的基是一个3×3的矩阵。故我们需要寻找到"最有用"的列作为基,而单纯形法中判断一列是不是有用,就是判断该列的检验数是否是负的,针对最小化问题。如果某列的检验数是负的,入基则会减少目标函数的值。所有的非基变量的检验数都大于等于0的话,此时的解为最优解。我们把寻找新列的问题叫子问题或者定价问题。针对 j j j列的检验数为:
r e d u c e   c o s t = c j − c B T B − 1 N j reduce~cost = c_j - \boldsymbol{c_B^TB^{-1}N_j} reduce cost=cjcBTB1Nj
其中 c B T B − 1 \boldsymbol{c_B^TB^{-1}} cBTB1是原问题的对偶变量的值, N j N_j Nj j j j列的基向量,在本问题中代表某种切割方案。设原问题的对偶变量为 y \boldsymbol{y} y,切割方案为 N j = ( a 1 , a 2 , a 3 ) ⊤ \boldsymbol{N_j} = (a_1,a_2,a_3)^\top Nj=(a1,a2,a3). 那么子问题可以写作:
min  1 − y T ( a 1 , a 2 , a 3 ) ⊤ s.t.  10 a 1 + 11 a 2 + 19 a 3 ≤ 80   a 1 , a 2 , a 3 ∈ Z + \begin{aligned} \text{min}~&1-\boldsymbol{y^T}(a_1,a_2,a_3)^\top \\ \text{s.t.}~&10a_1+11a_2+19a_3\leq80\ \\ &a_1,a_2,a_3\in\mathbb{Z}_+ \end{aligned} min s.t. 1yT(a1,a2,a3)10a1+11a2+19a380 a1,a2,a3Z+
列生成算法的步骤为:

  • 初始化:为主问题生成一个矩阵A,可以使用启发式的方法;
  • 重复:
    1. 求解限制性线性松弛的主问题,令 y ⊤ = c B T B − 1 \boldsymbol{y}^\top=\boldsymbol{c_B^TB^{-1}} y=cBTB1为该问题的对偶变量值。
    1. 求解背包问题类型的子问题,其最优值为 k k k
    1. 将子问题的最优解变成新列的系数加入限制性线性松弛的主问题。
  • 直到 k ≥ 0 k \geq 0 k0
列生成的缺点:
  • 线性松弛的最优解不一定原问题的最优解。

实验结果

问题规模求解方式最优目标函数值时间s
n=3kantorovich200.2093
n=3column generation200.01
n=10kantorovich613.97
n=10column generation630.01

总结

  1. kantorovich的建模方式求解速度较慢,但求解结果更准确。
  2. column generation的建模方式求解速度快,但求解结果不一定准确,获得是全局最优解的上界,介意这个gap的话可以采用分支定价算法。

本文python代码地址:https://github.com/gaopan812/OR_practice/tree/main/%E5%88%97%E7%94%9F%E6%88%90%E7%AE%97%E6%B3%95

参考文献

[1]孙小玲,李端.整数规划[M].科学出版社,2010.
[2]运筹优化常用模型、算法及案例实战——Python+Java实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾盼w(゚Д゚)w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值