整数规划_用下“分支定界法”解一解“整数规划”吧

本文介绍了整数规划及其与线性规划的区别,并重点讲解了分支定界法求解整数规划的过程,包括算法框架和代码实现。通过实例展示了如何应用分支定界法找到整数规划的最优解,并对比了商业求解器的结果。强调了松弛问题在整数规划求解中的重要性。
摘要由CSDN通过智能技术生成
e723c8fd4286fe6db2e26df2b74b72eb.gif e723c8fd4286fe6db2e26df2b74b72eb.gif e723c8fd4286fe6db2e26df2b74b72eb.gif为什么要做个整数规划的轮子呢?因为整数规划在实际应用中简直太普遍啦,而它的求解思路又很迷人,值得为之做一个轮子。

1df9ddf2bd9e813c971e56e5ea04da8a.png

    本文的内容:

  • 什么是整数规划,它与线性规划有什么差异,它的常用解法有哪些

  • 分支定界法的算法框架与代码框架

    本文的轮子能/不能支持的整数规划:

  • 支持最大化或最小化,无需手动化为最大化

  • 支持带不等号的约束,无需手动化为标准型

  • 不支持变量为负整数,需通过线性变换手动化为非负整数

    本文需要的前提知识:

  • 了解可行域的概念

  • 了解线性规划较易求解这个事实

Part1:整数规划简介 06080ce6cd2330fa1f5875c205a8f4ac.png

    整数规划(Integer Programming,IP)是指变量为整数的规划问题,如果约束条件和目标函数为线性表达式,那么就为整数线性规划(ILP),本文的整数规划特指整数线性规划。整数规划IP的数学模型为:

238f9908c0ae3ac87b2d8ef6b57be577.png

    再回忆下线性规划LP的数学模型:

707dcbdb683d645d9304c53d5503f144.png

    IP与LP在模型上的区别就只有一个:变量x为离散的整数还是为连续的实数。可见,IP与LP还是有千丝万缕的联系,这种联系也促成了IP的解法。

    一个实际的问题是:为什么我们需要让变量为离散的整数呢?这是因为实际的规划问题经常要求决策变量为整数,如买多少粒大白兔奶糖、买多少瓶可口可乐等等,这都要求结果是整数。

    另外一个实际的问题是:我们该怎样求解整数规划问题呢?毕竟让变量不偏不倚地成为一个整数显然是困难的。对此,我们需要使用一些常用的分析思路:

①分析可行域,问题的难点和优化思路一般围绕可行域展开。整数规划的难点就在于它的可行域是离散的,下图中一个个的黑点就表示一个个的可行解。通常来说,离散的可行域比连续的可行域要难分析许多。

75fd0f834c772a0f0561292182f11c61.png

②既然问题的难点在于离散的可行域,那么化难为易的关键就在于找到一个新问题,它的可行域是连续的,使得其容易求解;并且其最优解正好是整数规划的最优解,使得只计算新问题就可以得到整数规划的最优解。

③一般而言,要得到既容易求解,结果又与整数规划最优解相同的新问题,需要不断迭代地产生松弛问题。所谓松弛问题,是指可行域更大、因而更易求解的问题;所谓不断迭代,是指根据一个松弛问题的求解结果,来决定下一个松弛问题的形式。

④对于整数规划而言,松弛问题通常使用不考虑整数约束后得到的线性规划,比如说IP模型为:

238f9908c0ae3ac87b2d8ef6b57be577.png

那么松弛问题就是LP模型:

 707dcbdb683d645d9304c53d5503f144.png

    该松弛问题的可行域显然比原问题的可行域更大,符合松弛问题的基本条件;并且由于是连续的可行域,容易求解,也符合松弛问题存在的意义。

⑤对于整数规划而言,迭代产生松弛问题的方法主要有割平面法与分支定界法,二者的思路都是在松弛问题的基础上再加入新的约束,在不失去整数解的情况下,逐步缩小可行域。

关于IP的解法,包括但不限于:

    割平面法:不断地在同一个松弛问题上添加约束,直到最终的松弛问题能给出整数解为止。

  • Pros:一直只有一个松弛问题,内存占用较小。

  • Cons:以Gomory割平面法为例,其实际的收敛速度较慢;不为多项式时间算法。

    分支定界法:在一个松弛问题上,通过添加约束分支出两个新的松弛问题,以此类推,从而生成分支树,直到分支出的松弛问题能给出最优整数解为止。分支树如下图所示:(同时也会通过定界的方式来避免穷举庞大的树结构)

5fb0d79c5cfaf36c93f45f3a9c0f50e4.png

  • Pros:实际的收敛速度较快

  • Cons:由于要同时记录多个松弛问题,内存占用较大;不为多项式时间算法

Part2:分支定界法的算法框架 06080ce6cd2330fa1f5875c205a8f4ac.png

    分支定界法使用了经典的优化思想:如果一个优化问题约束复杂(如变量为整数),那么就忽略该约束、扩大可行域来生成松弛问题,然后对松弛问题不断迭代,直到最终的松弛问题给出了原问题的最优解为止。一个合格的松弛问题,必须做到可行域更大且容易解决;一个合格的迭代方法,必须做到不遗漏原问题可行域上的解。

    以最大化问题为例,分支定界法(Branch and Bound,B&B)的大体框架为:

4a39fe1491512a723f1403ecca4ec4d4.png

    用下图的整数规划为例介绍分支定界法:

886d0c6eaf9c981038428f65dbc27866.png

①先不考虑变量x1,x2为整数的约束,从而得到一个初始松弛问题z,如下图所示。我们可以轻易地解决如下这个线性规划问题,得到的解为x1=1/3,x2=1/3,z=2/3。

e2f8c7ef47c1313dc369bc8e92c5777d.png

②从不为整数的变量中随便选一个(统一起见,就选择下标最小的变量),本例中选择x1,之后按如下规则生成两个与x1相关的约束(这就是分支):

7339733716b61b763e7ae8f631fc6f9e.png

将这两个约束化简后分别加入到原来的松弛问题z中,就得到了两个新的松弛问题z1和z2:

           9d3e76b3b81fd7bb1ad27a65cf0fa009.png5caa3d8b14c5acef2cfdba79a1a7c60e.png

同时,原来的松弛问题z就不再考虑,直接删除。这样做能让松弛问题z1或z2更接近整数最优解的理由是:分开考虑x1<=0和x1>=1两种情况,没有让x1取整数的范围变小,从而不可能因此丢失掉任何整数解;同时,由于在原来的松弛问题z上加入了新约束,可行域会变小,因而更可能解出整数最优解。(搜索范围越小,找到目标的可能性就越大)

③现在还剩下z1,z2两个松弛问题,从中随便选一个先求解,本例中选择目标函数为z1的松弛问题求解。可以轻易地解决这个线性规划问题,得到的解为x1=0;x2=0.5,z1=0.5。得到的解依然不是整数解,故执行第②步,再次得到两个新的松弛问题z11和z12,并删除原来的松弛问题z1:

525269b6550dd65d895c31d170e9d341.png81982abf3614a328bcb0482187b30de8.png

④现在还剩下z2,z11,z12三个松弛问题,从中随便选一个先求解,本例选择目标函数为z11的进行求解,得到的解为x1=0,x2=0,z11=0。终于得到了第一个整数解,我们将整数解的目标函数值z11记录下来,作为LowerBound(LB),并直接删除z11松弛问题,不再进行分支。

⑤现在还剩下z2,z12两个松弛问题,从中随便选一个先求解,本例选择目标函数为z2的进行求解,得到的是不可行解,即比下界LB要差,故直接删除z2松弛问题,不再进行分支。(这就是定界,作用是直接删除不可能得到更优整数解的分支,从而避免穷举所有分支)

⑥现在还剩下z12一个松弛问题,对z12求解, 得到的是不可行解,即比下界LB要差,故直接删除z12松弛问题,不再进行分支。

⑦现在没有任何松弛问题存留,故得到的下界LB就是整数规划的最优值。对应的解x1=0,x2=0就是整数规划的最优解。

Part3:分支定界法的算法框架 d88446056354c74aaf4c022640b615a6.png

    上述内容更偏向于介绍分支定界的思路,从而忽略了完整性,实际上,分支定界理论还涉及到上界UpperBound(UB)的实现,松弛问题的求解顺序,这对算法的求解时间会有很大影响,这些内容都可在教材中找到。本文的代码框架为:

class MipSolver():
  def standTran(): 
    # 将最小化问题变成最大化问题

  def initialize ():
    # 得到初始的松弛问题列表Nodes,数据结构:列表
    # 得到初始的下界LB=负无穷
    # 得到初始的上界UB=正无穷
    initialize Nodes,LB,UB

  def solver():
    # 不断进行分支、定界工作
    # 直到松弛问题列表为空或者上下界的百分比差距小于gap(人为设定的值)
    while Nodes and (UB-LB)/LB       # node.preValue表示产生松弛问题node的原问题的最优值
      UB=max([node.preValue for node in Nodes]) 
      node=Nodes.pop() # 随便选一个松弛问题node
      value,solution=simplex(node) # 使用单纯形法快速求解
      if value# 若松弛问题node的最优值低于下界,就不再分支,这就是定界continue elif solutin is integer: # 如果松弛问题node的最优解为整数,则更新下界
        LB=valueelse: # 如果松弛问题node的最优解不为整数,则进行分支
        newNode1,newNode2=branch(node)
        Nodes+=[newNode1,newNode2]def main():# 主流程
    standTran()
    initialize ()
    solver()

    用以下整数规划的例子测试:

4129c45ab0680800b90172d7a8a17d47.png

    整数规划轮子的结果为:

a12310736b53c9d00dbac97fb12c5b4b.png

    商业求解器Lingo的结果为:

26f14b15bfb9c7e90d2b027da97eafc3.png

    求解结果没啥问题。关于此次整数规划的轮子,个人最大的收获是忽略变量为整数的条件,从而提出易解决的松弛问题;并通过不断加约束的方式来让松弛问题的解逐步靠近整数最优解,最终松弛问题的解就是整数规划最优解。这种“松弛思想”可以适用于许多其他方面,如求复杂函数或复杂规划的上下界;除了本文涉及的松弛方法,还有其他的松弛方法,也挺有意思的。

代码地址:https://github.com/aitexia/ORtools/tree/master/mip


-End-

小小Qiu

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值