赞
踩
作者:刘兴禄,清华大学,清华-伯克利深圳学院
初次完稿日期:2020.10.08
欢迎关注我们的微信公众号 运小筹
大规模混合整数规划(mixed integer programming, MIP)的求解在运筹优化中具有至关重要的地位。这里我们强调一下,不做特殊说明的话,我们考虑的都是混合整数线性规划(mixed integer linear programming, MILP)。求解MIP的常用精确算法主要包括:
branch and bound
cutting plane
branch and cut
column generation
(不保证得到最优解,需要结合其他技巧获得最优解)branch and price
Lagrangian relaxation
(不保证得到最优解,需要结合其他技巧获得最优解)Dantzig-Wolfe decomposition
Benders decomposition
其他衍生的拓展方法,本文不做介绍。
其中,branch and bound
、branch and cut
是非常通用的求解框架,适用于所有的MIP 。
Lagrangian relaxation
并不能保证得到最优解,但是运气好的时候,也可以得到最优解。不过Lagrangian relaxation
可以得到比线性松弛(LP relaxation)更紧的界限(Bound),因此可以用来加速branch and bound
或者branch and cut
。
而column generation
和branch and price
这两个框架的通用性就弱很多。这两个框架都是基于模型重构的。只有可以重构为相应问题的模型,才可以使用这两种方法。此外,column generation
不能保证获得全局最优解(具体原因可以查看相关文献,也可以阅读笔者即将出版的教材,见参考文献1)。而将branch and bound
的框架嵌入column generation
中,构成branch and price
框架,则可以保证获得全局最优解。
以上精确算法中:
branch and bound
是一种分而治之的思想,本质上是一种隐枚举(branching)。但是由于加入了prune(剪枝)
和bounding(定界)
的步骤,使得该框架在实际求解中要比真正的纯枚举要高效得多。branch and cut
是目前最流行的求解MIP的求解器的通用算法框架。由于其在branch and bound
的基础上,加入了cutting plane
的步骤,用于割去当前节点的最优小数解,从而逼近该节点的凸包,从而显著地加速了求解过程。column generation
和branch and price
是基于模型重构
而来的算法。通常是将原来的MIP分解成为一个主问题(Master Problem)和若干个子问题(Subproblem),然后迭代求解。当然,子问题又叫定价子问题(Pricing Problem)。由于分解之后,各个部分的求解相对容易,以及主问题一般是更为紧凑的模型,因此会提供更好的界限,从而加速收敛。这些框架都是融合了模型重构和分解的思想。Lagrangian relaxation
是一种松弛的思想。通过结合对偶理论,得到比单纯的线性松弛更好的界限。Dantzig-Wolfe decomposition
和Benders decomposition
是根据模型的特殊结构,将模型分解为更容易求解的小问题,通过小问题之间的迭代求解和交互,最终达到精确求解模型的目的的精确算法。但是二者的分解思路并不相同。Dantzig-Wolfe decomposition
是基于一个表示定理得来的分解方法,该方法需要MIP的约束矩阵符合块角状的特征,通用性有限,使用之前需要考察模型是否符合该结构。而Benders decomposition
实际上是较为通用的分解框架,CPLEX中也包含了Benders decomposition
的算法组件,用户可以自己定制分解策略。Benders decomposition
的主要思想是,将较复杂的模型分解成为2部分,分别求解2部分都较为容易,通过两部分之间的交互迭代,最终算法得到收敛,得到最优解。每一种精确算法都不存在绝对的优劣
关系,它们各有特点,都蕴含着精妙的思想。在实际情况中,我们需要灵活应用,巧妙结合,从而达到显著加速求解的目的。
本文就来着重介绍分解算法
中的重要成员: Benders decomposition
。这里强调一下,本文涉及的Benders decomposition
,是最基本的Benders decomposition
,更高级别的Benders decomposition
的拓展算法,请读者自行阅读相关文献。
上面讲到,分解算法,是基于模型的特点,将大问题拆解称为若干小问题。单独求解这些小问题的难度,远低于直接求解原来的大模型。这些小问题之间需要进行一定的交互,从而保证整分解后的模型能够收敛到原来模型的最优解,从而保证分解方法的全局最优性。
这里需要明确,分解
≠ \ne =拆解
。分解的操作,实际上是很有艺术性和理论性的。
分解包括拆解
+ + +耦合
。其中拆解
就是将问题拆成若干小问题,耦合
就是将各个小问题联系起来,形成交互,从而保证全局最优性。
也许目前的直观解释还不够具体,不过没关系,我们先说清楚整体的思想,然后再以具体的理论加以解释。
考虑如下的MIP模型:
min x , y c x + f y s.t. A x + B y = b x ⩾ 0 y ∈ Y ⊆ R n
其中 c ∈ R 1 × m , f ∈ R 1 × n c \in \mathbb{R}^{1\times m}, f \in \mathbb{R}^{1\times n} c∈R1×m,f∈R1×n,是行向量, x , y x, y x,y是列向量,且 x , y x, y x,y是决策变量,其维度分别为 m × 1 m\times 1 m×1和 n × 1 n\times 1 n×1。 A , B A, B A,B是约束矩阵,其维度分别为 A ∈ R r × m , B ∈ R r × n A\in \mathbb{R}^{r\times m}, B\in \mathbb{R}^{r\times n} A∈Rr×m,B∈Rr×n。 b b b为右端常数,其维度为 b ∈ R r × 1 b\in \mathbb{R}^{r\times 1} b∈Rr×1。注意这里的符号, R r × m \mathbb{R}^{r\times m} Rr×m其实就是表示是一个 r × m r \times m r×m的一个实数矩阵。
该MIP模型具有下面的特点:
continuous
)决策变量,较为简单;binary
)决策变量或者整数(integer
)型决策变量,相较 x x x而言,略复杂,因此在模型中我们用了数学语言 y ∈ Y ⊆ R n y \in Y \subseteq \mathbb{R}^n y∈Y⊆Rn来表达。前一个 y ∈ Y y \in Y y∈Y,这个 Y Y Y可以是一系列的 y ∈ { 0 , 1 } y \in \{0,1\} y∈{
0,1}的约束,也可以是 y integer y \text{ integer} y integer的约束。当然,还可以是 y ⩾ 0 y \geqslant 0 y⩾0的连续约束,都可以。为了方便,我们统一用 y ∈ Y y \in Y y∈Y来表示。由于 x x x为简单变量
, y y y为复杂变量
,当规模较大时,直接求解上述MIP比较困难。这个困难的原因是:
复杂变量
y y y搅合进来了,这个罪魁祸首给问题求解带来了挑战。
因此我们设想:如果我们将这个捣蛋者
y y y先搞定,剩下的部分中,只有
x x x是决策变量,问题就变成了线性规划(Linear programming, LP)了,这不就简单太多了嘛?
Benders Decomposition
就是基于这样的思想。
我们观察到,如果给定 y y y的值,假定为 y ˉ \bar{y} yˉ,那么剩余部分的模型就可以写成
SP: min x c x s.t. A x = b − B y ˉ x ⩾ 0
该模型是LP,求解难度比之前的MIP降低了好几档次。因为MIP是NP-hard问题,而LP是多项式时间可精确求解的,不是NP-hard
。该问题一般被称之为子问题(Subproblem problem, SP)
。
如何给出 y y y的值 y ˉ \bar{y} yˉ呢?我们可以将关于 x x x的部分全部忽略掉,变成下面的模型
MP 0 : min y f y s.t. y ∈ Y ⊆ R n
求解 MP 0 \text{MP}_0 MP0非常容易,求解得到的解,即可作为 y ˉ \bar{y} yˉ传给 SP \text{SP} SP。
该问题一般被称之为主问题(Masterproblem, MP)
。 MP 0 \text{MP}_0 MP0加了下标0表示初始的 MP \text{MP} MP(因为后续迭代过程,MP需要加入cut
)。
但是,分别求解模型 MP \text{MP} MP和 SP \text{SP} SP并不能等同于求解了原MIP。要想达到等价地求解原MIP的目的,还需要 MP \text{MP} MP和 SP \text{SP} SP之间的交互。
为什么要交互呢?
原因是:
试错
,再补救
的过程,先删除所有的 x x x的相关部分,构成初始的 MP \text{MP} MP,通过求解 SP \text{SP} SP,获得一些信息,这些信息反映了 x x x对 y y y的影响,我们通过某种方式,将 x x x对 y y y的影响加回到 MP \text{MP} MP中,进行补救
。通过整个过程的迭代,我们最终就可以达到求解原MIP的目的。其中,补救
的步骤,实际上专业术语叫做recourse
,反应在具体形式上,就是以cutting plane
的形式,将补救措施
加回到 MP \text{MP} MP中。
至于如何补救补救
,那就需要用到对偶理论
的知识。首先说明,Benders Decomposition分解的补救措施,是以两种cutting plane
的形式加回到 MP \text{MP} MP中的,分别为
Benders optimality cut
和Benders feasibility cut
。这两种Cut来源于 SP \text{SP} SP的对偶,由于 SP \text{SP} SP是LP,因此我们可以将 SP \text{SP} SP对偶,变成 Dual SP \text{Dual SP} Dual SP,其形式如下:
Dual SP: max α α T ( b − B y ˉ ) s.t. A T α ⩽ c α free
我们可以观察到:
这里我们不加证明的给出Benders optimality cut
和Benders feasibility cut
的具体形式。(为什么不加证明呢?是小编不会嘛?当然不是,是太麻烦了,小编在自己写的教材里面给出了非常详细的论述,大家可以去自行查看。或者可以阅读下面的参考文献。)
Benders optimality cuts
的具体形式为
( α p i ) T ( b − B y ) ⩽ q , ∀ i ∈ P
其中, P \mathcal{P} P表示迭代过程中找到的子问题的对偶问题 Dual SP \text{Dual SP} Dual SP的极点(extreme point
,其实就是最优解)的集合, α p i \alpha_p^i αpi就表示 Dual SP \text{Dual SP} Dual SP的一个极点。
Benders feasibility cuts
的具体形式为
( α r i ) T ( b − B y ) ⩽ 0 , ∀ i ∈ R
其中, R \mathcal{R} R表示迭代过程中找到的子问题的对偶问题 Dual SP \text{Dual SP} Dual SP的极射线(extreme ray
,其实就是无界射线)的集合, α r i \alpha_r^i αri就表示 Dual SP \text{Dual SP} Dual SP的一个极射线。
这里,我们省去具体的理论论证部分,直接给出简洁的结论。完整,详细的理论介绍,参见文献
- Zeki Caner Taşkin. Benders Decomposition. American Cancer Society, 2011. ISBN 9780470400531.
此外,笔者即将出版的教材《运筹优化常用模型、算法与案例实战——Python+Java实现》第17章
Benders分解算法
给出了更为详尽、直观的解释,可以帮助读者更容易理解详细的原因。待出版之后,有兴趣的读者可以去查看。
Benders Decomposition
的完整步骤如下:
主问题(Master problem, MP)
和一个子问题(Subproblem problem, MP)
。 MP \text{MP} MP如下这里, Benders optimality cuts \text{Benders optimality cuts} Benders optimality cuts的具体形式为
( α p i ) T ( b − B y ) ⩽ q , ∀ i ∈ P(αpi)T(b−By)⩽q,∀i∈P(αip)T(b−By)⩽q,∀i∈P
其中, P \mathcal{P} P表示迭代过程中找到的子问题的对偶问题 Dual SP \text{Dual SP} Dual SP的极点的集合, α p i \alpha_p^i αpi就表示 Dual SP \text{Dual SP} Dual SP的一个极点。Benders feasibility cuts \text{Benders feasibility cuts} Benders feasibility cuts的具体形式为
( α r i ) T ( b − B y ) ⩽ 0 , ∀ i ∈ R(αri)T(b−By)⩽0,∀i∈R(αir)T(b−By)⩽0,∀i∈R
其中, R \mathcal{R} R表示迭代过程中找到的子问题的对偶问题 Dual SP \text{Dual SP} Dual SP的极射线(extreme ray
)的集合, α r i \alpha_r^i αri就表示 Dual SP \text{Dual SP} Dual SP的一个极射线。
操作方法1:
根据 y ˉ \bar{y} yˉ构建子问题的对偶问题 Dual SP \text{Dual SP} Dual SP
Dual SP: Q ( y ) = max α α T ( b − B y ˉ ) s.t. A T α ⩽ c α freeDual SP:Q(y)=αmaxs.t.αT(b−Byˉ)ATα⩽cα freeDual SP:Q(y)=maxαs.t.αT(b−By¯)ATα⩽cα free
优点
:得到对偶变量方便,直接就是决策变量的取值。
缺点
:需要写出子问题的对偶。
操作方法2:
这里,也可以不构建 Dual SP \text{Dual SP} Dual SP,直接只构建 SP \text{SP} SP即可。即,只需要构建:
SP: Q ( y ) = min x c x s.t. A x = b − B y ˉ x ⩾ 0SP:Q(y)=xmins.t.cxAx=b−Byˉx⩾0SP:Q(y)=minxs.t.cxAx=b−By¯x⩾0
优点
:不用写出子问题的对偶,建模方便。
缺点
:CPLEX需要用IloCplex.getDuals()
获取约束的对偶变量,需要用IloCplex.dualFarkas()
函数获得约束的极射线; Gurobi中需要使用Constr.Pi
获取约束的对偶变量,需要用Constr.FarkasDual
获取约束的极射线。其实这个也不算啥缺点。
Benders optimality cut
和Benders feasibility cut
。这里也有2种等价的操作。操作方法1:
求解 Dual SP \text{Dual SP} Dual SP,直接得到 α \alpha α。
- 如果子问题的对偶 Dual SP \text{Dual SP} Dual SP存在有界的可行解,则构建
Benders optimality cut
:
( α ) T ( b − B y ) ⩽ q(α)T(b−By)⩽q(α)T(b−By)⩽q - 如果子问题的对偶 Dual SP \text{Dual SP} Dual SP无界,则构建
Benders feasibility cut
( α ) T ( b − B y ) ⩽ 0(α)T(b−By)⩽0(α)T(b−By)⩽0
操作方法2:
直接求解 SP \text{SP} SP的原始形式,然后用求解器得到 SP \text{SP} SP的约束的对偶变量 α p \alpha_p αp或者极射线 α r \alpha_r αr。
- 如果子问题本身 SP \text{SP} SP
存在有界的可行解
,则构建Benders optimality cut
:
( α ) T ( b − B y ) ⩽ q(α)T(b−By)⩽q(α)T(b−By)⩽q - 如果子问题本身 SP \text{SP} SP
无可行解
,则构建Benders feasibility cut
( α ) T ( b − B y ) ⩽ 0(α)T(b−By)⩽0(α)T(b−By)⩽0
Benders optimality cut
和Benders feasibility cut
添加到 MP \text{MP} MP中。求解 MP \text{MP} MP,并更新全局的上界 U B UB UB和全局的下界 L B LB LB。如果 U B = L B UB=LB UB=LB,则算法停止,获得最优解,否则,循环2-4步。这里需要说明,全局的 U B UB UB和 L B LB LB的计算方法如下:
U B = f y + Q ( y ) L B = f y + qUB=fy+Q(y)LB=fy+qUB=fy+Q(y)LB=fy+q
这是为什么呢?因为 f y + Q ( y ) fy + Q(y) fy+Q(y),是给定了 y = y ˉ y=\bar{y} y=yˉ之后,求解 SP \text{SP} SP,得到 x x x的值 x ˉ \bar{x} xˉ,因此 ( x ˉ , y ˉ ) (\bar{x}, \bar{y}) (xˉ,yˉ)是原问题MIP的一个可行解。 min \min min问题的任意一个可行解,一定是原问题的 U B UB UB,因此
U B = f y + Q ( y )UB=fy+Q(y)UB=fy+Q(y)
。而 f y + q fy + q fy+q是忽略了 x x x的影响,只是添加了一部分的Benders optimality cut
和Benders feasibility cut
,并没有将所有的Cuts都加回来。因此它是原问题的一个松弛版本,因此可以为原问题提供一个下界。因此
L B = f y + qLB=fy+qLB=fy+q
当
U B = L B UB=LB UB=LB时,我们就得到了全局最优解,此时正好满足
f y + q = L B = U B = f y + Q ( y )fy+q=LB=UB=fy+Q(y)fy+q=LB=UB=fy+Q(y)
也就是
q = Q ( y )q=Q(y)q=Q(y)
因此,比较简洁的判断Benders Decomposition
是否得到最优解的办法,就是判断主问题中的 q q q的取值,是否和子问题的目标函数 Q ( y ) Q(y) Q(y)相同。
但是大家需要知道为什么是 q = Q ( y ) q = Q(y) q=Q(y)。背后的原因,在上面的文字中已经给出了详细的理论解释。
直观上来讲,Benders Decomposition的总体框架如下。
基于此,我们给出Benders Decomposition
的伪代码,方便后面的代码实现(注意,伪代码是基于 min \min min问题的,如果是 max \max max问题,可以相应做对应变化即可):
文献[2]中给出了一个详细的例子,但是我觉得本文介绍的例子也许更适合来结合代码和可视化工具进行介绍。
该例子参考自网址:https://www.youtube.com/watch?app=desktop&v=vQzpydNOWDY
- Ray (Jian) Zhang. Learn Optimization Visually: Benders Decomposition. url: https://www.youtube.com/watch?app=desktop&v=vQzpydNOWDY
具体描述如下(有改动):
小王拥有1000元现金流。他需要优化自己的理财计划,使得自己的收益最大化。他有以下两类选择。
- 小王可以将钱存入银行储蓄账户,储蓄账户的固定收益率为4.5%。但是储蓄账户只允许存储整数数量的资金。
- 小王还可以购买基金。假设一共有10个基金可选,分别为 F 1 , F 2 , ⋯ , F 10 F_1, F_2, \cdots, F_{10} F1,F2,⋯,F10,每个基金的收益率分别为1%, 2%, … 10%。每种基金最多购买100元。
问:小王应该如何投资,才能最大化自己的收益。
本问题的最优解为:
小王应该分别购买100元的 F 5 , F 6 , F 7 , ⋯ , F 10 F_5, F_6, F_7, \cdots, F_{10} F5,F
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。