pyscipopt中SCIP分支过程修改参数及节点触发更新方法
实现方法
你不需要在分支处理程序里实现这个逻辑,SCIP的事件处理器(Eventhdlr)就是专门用来在求解流程的特定节点注入自定义操作的,注册流程和你之前写分支处理器的逻辑基本一致,只是监听的触发事件不同。
针对你要的两个触发规则,对应监听的事件类型如下:
- 每次找到可行解(新的incumbent解出现)时触发:监听
SCIP_EVENTTYPE.BESTSOLFOUND事件即可 - 每遍历N个节点触发:监听节点处理完成类事件(
SCIP_EVENTTYPE.NODEFEASIBLE、SCIP_EVENTTYPE.NODEINFEASIBLE,分别对应节点判定可行、不可行的完成节点),回调内累计已处理节点数,达到间隔阈值时执行参数更新即可。
可直接运行的参考代码
from pyscipopt import Model, Eventhdlr, SCIP_EVENTTYPE class DynamicParamUpdater(Eventhdlr): def __init__(self, node_update_interval=10): super().__init__() self.interval = node_update_interval self.processed_node_cnt = 0 def eventinit(self): # 注册需要监听的事件 self.model.catchEvent(SCIP_EVENTTYPE.BESTSOLFOUND, self) self.model.catchEvent(SCIP_EVENTTYPE.NODEFEASIBLE | SCIP_EVENTTYPE.NODEINFEASIBLE, self) def eventexit(self): # 求解结束前释放事件监听 self.model.dropEvent(SCIP_EVENTTYPE.BESTSOLFOUND, self) self.model.dropEvent(SCIP_EVENTTYPE.NODEFEASIBLE | SCIP_EVENTTYPE.NODEINFEASIBLE, self) def eventexec(self, event): trigger_update = False ev_type = event.getType() # 匹配找到可行解的触发规则 if ev_type == SCIP_EVENTTYPE.BESTSOLFOUND: trigger_update = True # 匹配节点数间隔的触发规则 if ev_type in (SCIP_EVENTTYPE.NODEFEASIBLE, SCIP_EVENTTYPE.NODEINFEASIBLE): self.processed_node_cnt += 1 if self.processed_node_cnt % self.interval == 0: trigger_update = True if trigger_update: # 在此处写入你要修改的参数逻辑即可,和求解前设置参数的调用方式完全一致 # 示例:动态调低RINS启发式的调用频率 current_rins_freq = self.model.getIntParam("heuristics/rins/freq") self.model.setIntParam("heuristics/rins/freq", max(1, current_rins_freq - 1)) # 调用示例 if __name__ == "__main__": model = Model("dynamic_param_demo") # 按常规流程添加变量、约束、设置目标函数 # ...... # 注册自定义事件处理器 updater = DynamicParamUpdater(node_update_interval=10) model.includeEventhdlr(updater, "dynamicParamHdlr", "求解过程动态更新参数") model.optimize()
注意事项
- 所有求解控制类参数(比如启发式调用频率、割平面开关、分支规则优先级、节点选择权重、相对gap阈值这类)都可以在事件回调里直接调用
setXxxParam接口修改,不需要额外做状态同步,修改后会立刻在后续求解流程生效。不要在回调里直接修改和模型结构相关的内容(比如增减变量、修改变量类型),这类操作要走约束添加、分支规则的专门接口。 - 你之前推测的“和添加约束逻辑相近”只对了一半:两者都是通过自定义SCIP插件注入逻辑,但适用插件类型不同——分支阶段加约束要靠分支处理器/约束处理器,动态修改求解参数用事件处理器是最轻量的实现方式,不需要侵入分支判定逻辑。
参考资料来源
- pyscipopt官方示例库的
examples/eventhdlr.py文件包含事件处理器的基础写法,可以直接对照修改 - 所有可监听的事件类型、可动态修改的参数列表,都可以在pyscipopt自带的接口文档、SCIP官方参数列表里查到,不需要找特殊的分支阶段改参数的示例,参数修改本身不要求必须在分支回调内执行。
内容的提问来源于stack exchange,提问作者orpanter
相关产品推荐
相关产品推荐

