Callbacks功能¶
杉数求解器COPT提供Callbacks(回调)功能,支持用户在混合整数规划分支切割的求解过程中,获取中间信息(如当前最优下界、当前最优目标值等);以及控制求解进程:如修改模型(如添加惰性约束、添加割平面),终止求解等。目前支持使用Callbacks的问题类型有:混合整数规划、混合二阶锥规划、混合整数二次(约束)规划。
本章节的内容构成如下:
获取MIP求解过程中间信息¶
MIP求解过程中,可获取到的中间信息取决于Callback Context(Callback的触发点),支持的Context如下:
CBCONTEXT_MIPSOL:当找到MIP可行解时,触发回调函数;CBCONTEXT_MIPRELAX:当找到MIP线性松弛解时,触发回调函数;CBCONTEXT_MIPNODE:当处理完成MIP节点并求解LP松弛问题完成时,触发回调函数。
COPT支持获取的Callback信息,详细请参考 Callback相关信息 部分。
对应关系罗列如下表:
Context |
Callback Information |
|---|---|
|
|
|
|
|
|
除此之外的 BestObj, BestBnd, HasIncumbent, Incumbent 在任何触发点都可以被获取(即 CBCONTEXT_MIPSOL, CBCONTEXT_MIPRELAX, CBCONTEXT_MIPNODE 均可)。
注意
如果
HasIncumbent == False, 则无法获取Incumbent。信息
NodeStatus的返回值为常数,表示当前节点LP松弛问题的求解状态,可取值请参考: 一般常数章节:解状态(部分) 。
对于 可行解 , LP松弛解 , 当前最优可行解 这三项信息,不同接口中的获取方式有所不同:
C语言:通过函数
COPT_GetCallbackInfo,需获取的中间信息名称作为函数的参数提供;面向对象的编程语言(C++/C#/Java/Python)中,
CallbackBase类提供专门的函数,以获取相应中间信息。
面向对象的编程语言(C++/C#/Java/Python)中,
CallbackBase.getInfo(infoname)函数,仅支持获取标量类型的信息常数,即:NodeStatus,MipCandObj,RelaxSolObj,BestObj,BestBnd,HasIncumbent。 其他的非标量信息提供专门的函数获取。以Python接口为例,将对应函数名称罗列如下。其他编程语言接口类似,可参考各API的
CallbackBase类。获取当前可行解:
CallbackBase.getSolution()获取当前LP松弛解:
CallbackBase.getRelaxSol()获取当前最优可行解:
CallbackBase.getIncumbent()
控制MIP求解进程¶
COPT提供相关函数,让用户在MIP分支切割法的求解过程中,交互式地添加惰性约束或割平面,以控制MIP求解进程。主要有如下三类操作:
添加惰性约束
添加割平面
设置自定义的可行解
添加惰性约束¶
COPT支持用户通过两种方式添加惰性约束,一种是直接向模型中添加,另一种是通过Callback在求解过程中,在指定的Callback Context中添加。
在C API中,根据函数名称中是否包含 "Callback" 进行区分;在面向对象的API中,分别对应 Model 类和 CallbackBase 的函数。
在求解之前,直接向模型中添加,支持添加单边或双边的惰性约束。以Python为例:
添加单个:Model.addLazyConstr()
批量添加多个:Model.addLazyConstrs()
在求解过程中,通过Callback,根据Callback Context动态添加,仅支持添加单边的惰性约束。以Python为例:
添加单个:CallbackBase.addLazyConstr()
批量添加多个:CallbackBase.addLazyConstrs()
添加割平面¶
同样,对于割平面,COPT也支持上述两种添加方式。
在求解之前,直接向模型中添加,支持添加单边或双边的割平面约束。以Python为例:
添加单个:Model.addUserCut()
批量添加多个:Model.addUserCuts()
在求解过程中,通过Callback,根据Callback Context动态添加,仅支持添加单边的割平面约束。以Python为例:
添加单个:CallbackBase.addUserCut()
批量添加多个:CallbackBase.addUserCuts()
注意
在Callback中调用Model类添加惰性约束和用户割平面是无效的。
设置自定义的可行解¶
COPT的callback功能支持在MIP求解过程中,添加用户自定义的可行解(可以是用户通过任意方式找到的可行解,例如通过启发式算法)。以Python为例:
设置自定义的可行解:
CallbackBase.setSolution(vars, val)将自定义的解加载到模型中:
CallbackBase.loadSolution()
注意
当前支持设置完整的可行解。
同样,操作修改模型的函数需要在指定的Callback Context中才能被调用。
以python为例,CallbackBase 类中的成员函数,以及对应可调用的Context罗列如下:
Context |
函数 |
|---|---|
CBCONTEXT_MIPSOL |
|
CBCONTEXT_MIPRELAX |
|
CBCONTEXT_MIPNODE |
|
注意
其他编程语言API的函数调用形式略有不同,但对应关系是一致的。C语言章节也罗列了Callback相关函数及Callback Context的对应关系, 详细请参考 C API:回调功能函数 。
不同API中使用Callback功能¶
以面向对象的编程接口为例,展示在不同的API中,调用Callback功能的基本步骤:
构建自定义Callback类,并继承
CallbackBase类;实现
CallbackBase.callback()函数,在其中自定义需要进行的操作(获取中间信息或者添加惰性约束/割平面等);新建自定义Callback实例,并传入用户需要的参数;
通过Model类的
Model.setCallback()添加Callback实例,并将Callback Context作为参数输入。
后续在求解过程中,在指定的Callback Context中,则会触发调用Callback实例中,用户自定义的callback函数。
在各编程语言API中的具体实现也类似,以Python为例,可以参考安装包中examples目录中的的示例代码 "cb_ex1.py" 。
回调函数在不同编程接口中的调用方式和函数名称 略有不同 ,但是支持的功能和函数含义是一致的,请进一步参考不同编程接口API参考手册的对应章节,以获取具体介绍:
C API:回调功能函数
C++ API:CallbackBase类
C# API:CallbackBase类
Java API:CallbackBase类
Python API:CallbackBase类