我有二进制和连续变量的MILP问题。我想使用Benders的分解算法来解决它。我正在关注此演示文稿:http://www.iems.ucf.edu/qzheng/grpmbr/seminar/Yuping_Intro_to_BendersDecomp.pdf
我将问题分为由离散变量组成的主问题和具有连续变量的从问题。
基于ATSP示例:https://github.com/cswaroop/cplex-samples/blob/master/bendersatsp.py
,我正在使用CPLEX Python API来解决它在这个示例中,我创建了主控问题和从属对偶。
我使用BendersLazyConsCallback
,但不确定我是否完全理解。请帮助我。
获得当前主解决方案时,将调用函数separate
,然后更新对偶目标函数,并重新解决对偶问题。
如果对偶是无界的,则它将射线添加到主问题约束中,例如self.add(constraint = workerLP.cutLhs, sense = "L", rhs = workerLP.cutRhs)
,发生在BendersLazyConsCallback
类中。
但是当对偶最优时,该示例不包含代码。 因此,当对偶最优时,我会添加一个相似的调用,并根据对偶解将约束添加到主问题。
但是,如果我尝试打印主要问题约束,例如problem.linear_constraints.get_rows()
,则看不到新包含的约束。看来self.add(constraint = workerLP.cutLhs, sense = "L", rhs = workerLP.cutRhs)
命令不会将其推送到主约束,而是将其保留为LazyConstraintCallback
类的成员。它是否正确?我怎么能看到这些新约束实际上是添加的?
此外,算法如何停止?在传统的Benders算法中,问题的下界和上限是根据对偶解和主解进行更新的,当它们相等时,我们便会收敛。
在ATSP示例中,我看不到发生了什么。 BendersLazyConsCallback
的确切触发时间以及如何知道何时停止?
答案 0 :(得分:0)
您上面链接的示例来自CPLEX 12.6。到目前为止,这已经很旧了(当前最新版本为12.9)。如果您尚未更新到最新版本,那么这样做可能是一个好主意。更新的原因之一是,使用CPLEX 12.7支持automatic Benders' decomposition。使用CPLEX 12.8,有一个新的generic callback(还有一个新的bendersatsp2.py
示例来演示它)。
话虽如此,我将尝试回答您的其他一些问题。
首先,如here所述,如果您写出模型,它将不包含您在回调中动态添加的惰性约束。您可以很容易地自己在回调中将它们打印出来(例如print("LC:", workerLP.cutLhs, "G", workerLP.cutRhs)
。您可以通过在引擎日志末尾显示一条消息来确定是否已应用约束,例如:
应用用户削减:3
关于有关惰性约束如何工作的最终问题,请参阅《 CPLEX用户手册》中的legacy callbacks一节。另外,在termination conditions of the MIP optimizer上有一节。每当CPLEX找到整数可行的解决方案时,就会调用惰性约束回调(有关更多信息,请参见IBM developerWorks论坛上的this线程)。