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

CBCONTEXT_MIPSOL

MipCandObj, MipCandidate

CBCONTEXT_MIPRELAX

RelaxSolution, RelaxSolObj

CBCONTEXT_MIPNODE

NodeStatus, RelaxSolution, RelaxSolObj, MipCandObj, MipCandidate

除此之外的 BestObj, BestBnd, HasIncumbent, Incumbent 在任何触发点都可以被获取(即 CBCONTEXT_MIPSOL, CBCONTEXT_MIPRELAX, CBCONTEXT_MIPNODE 均可)。

注意

  1. 如果 HasIncumbent == False , 则无法获取 Incumbent

  2. 信息 NodeStatus 的返回值为常数,表示当前节点LP松弛问题的求解状态,可取值请参考: 一般常数章节:解状态(部分)

  1. 对于 可行解LP松弛解当前最优可行解 这三项信息,不同接口中的获取方式有所不同:

    • C语言:通过函数 COPT_GetCallbackInfo ,需获取的中间信息名称作为函数的参数提供;

    • 面向对象的编程语言(C++/C#/Java/Python)中, CallbackBase 类提供专门的函数,以获取相应中间信息。

  2. 面向对象的编程语言(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求解进程。主要有如下三类操作:

  1. 添加惰性约束

  2. 添加割平面

  3. 设置自定义的可行解

添加惰性约束

COPT支持用户通过两种方式添加惰性约束,一种是直接向模型中添加,另一种是通过Callback在求解过程中,在指定的Callback Context中添加。 在C API中,根据函数名称中是否包含 "Callback" 进行区分;在面向对象的API中,分别对应 Model 类和 CallbackBase 的函数。

  1. 在求解之前,直接向模型中添加,支持添加单边或双边的惰性约束。以Python为例:

    • 添加单个:Model.addLazyConstr()

    • 批量添加多个:Model.addLazyConstrs()

  2. 在求解过程中,通过Callback,根据Callback Context动态添加,仅支持添加单边的惰性约束。以Python为例:

    • 添加单个:CallbackBase.addLazyConstr()

    • 批量添加多个:CallbackBase.addLazyConstrs()

添加割平面

同样,对于割平面,COPT也支持上述两种添加方式。

  1. 在求解之前,直接向模型中添加,支持添加单边或双边的割平面约束。以Python为例:

    • 添加单个:Model.addUserCut()

    • 批量添加多个:Model.addUserCuts()

  2. 在求解过程中,通过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

CallbackBase.addLazyConstr CallbackBase.addLazyConstrs CallbackBase.getSolution CallbackBase.setSolution CallbackBase.getIncumbent CallbackBase.getInfo

CBCONTEXT_MIPRELAX

CallbackBase.addUserCut CallbackBase.addUserCuts CallbackBase.getRelaxSol CallbackBase.getIncumbent CallbackBase.setSolution CallbackBase.getInfo

CBCONTEXT_MIPNODE

CallbackBase.getRelaxSol CallbackBase.getIncumbent CallbackBase.setSolution CallbackBase.getInfo

注意

其他编程语言API的函数调用形式略有不同,但对应关系是一致的。C语言章节也罗列了Callback相关函数及Callback Context的对应关系, 详细请参考 C API:回调功能函数

不同API中使用Callback功能

以面向对象的编程接口为例,展示在不同的API中,调用Callback功能的基本步骤:

  1. 构建自定义Callback类,并继承 CallbackBase 类;

  2. 实现 CallbackBase.callback() 函数,在其中自定义需要进行的操作(获取中间信息或者添加惰性约束/割平面等);

  3. 新建自定义Callback实例,并传入用户需要的参数;

  4. 通过Model类的 Model.setCallback() 添加Callback实例,并将Callback Context作为参数输入。

后续在求解过程中,在指定的Callback Context中,则会触发调用Callback实例中,用户自定义的callback函数。

在各编程语言API中的具体实现也类似,以Python为例,可以参考安装包中examples目录中的的示例代码 "cb_ex1.py"

回调函数在不同编程接口中的调用方式和函数名称 略有不同 ,但是支持的功能和函数含义是一致的,请进一步参考不同编程接口API参考手册的对应章节,以获取具体介绍: