SCIP求解MILP问题时如何设置初始猜测及代码疑问
我在使用SCIP库时,因文档不完善,无法理清设置初始猜测的方法调用流程。现有一个包含n个整数与连续变量及约束的MILP问题,需求是:先求解该问题得到最优解,再向问题中添加一个新变量及相关约束,将原最优解作为n+1变量新问题的部分初始猜测。我设想的实现代码如下:
SCIPsolve(scipeEnv); // 求解含n个变量的问题 SCIP_Sol *sol = SCIPgetBestSol(scipEnv); // 获取最优解 SCIP_Sol *copiedSol = nullptr; // 最优解的副本 SCIPcreateSolCopy(scipEnv, copiedSol, sol); // 复制最优解 // [1] 复制得到的解是否与原问题关联,转换原问题状态时是否需要解绑? // [2] 是否必须进行解的复制操作? SCIPfreeTransform(scip); // 将问题转换回原始状态 // *** 向问题中添加新变量及相关约束 *** SCIPcreatePartialSol(scip, &copiedSol, nullptr); // [3] 是否通过以下流程创建初始猜测:获取最优解→复制解→基于复制解创建部分解? // 还是需要将最优解的值提取到临时双精度变量中,再创建部分解并传入这些值? SCIP_Bool stored; SCIPaddSolFree(scipEnv, &copiedSol, &stored);
疑问解答
[1] 复制得到的解是否与原问题关联,转换原问题状态时是否需要解绑?
复制得到的copiedSol与原转换后的问题强绑定。调用SCIPfreeTransform将问题转回原始状态时,原转换问题的内存会被释放,绑定在它上面的解会直接失效。因此,必须在调用SCIPfreeTransform前,要么解绑复制的解,要么提前提取解中的变量值——后者更稳妥,因为解绑操作容易出错。
[2] 是否必须进行解的复制操作?
是的,必须复制。SCIPgetBestSol返回的是SCIP内部管理的解对象,当你修改问题结构(比如添加变量)或释放转换状态时,这个内部解会被销毁或标记为无效。复制解可以把解的内容独立出来,避免后续操作导致原始最优解不可用。另外注意:你代码里的SCIPcreateSolCopy调用有误,正确格式是SCIPcreateSolCopy(scip, &copiedSol, sol);——第二个参数需要传指针的指针,否则无法正确分配内存。
[3] 两种初始猜测设置方式的可行性
你设想的流程不可行,因为SCIPcreatePartialSol是创建新的空部分解,不是基于已有解修改;而且原复制的解在SCIPfreeTransform后已经失效,无法复用。更可靠的方式是提取原最优解的变量值,再为新问题创建部分解并赋值:
- 遍历原问题所有变量,用
SCIPgetSolVal提取每个变量在最优解中的值,存入临时数组; - 添加新变量与约束后,调用
SCIPcreatePartialSol创建空的部分解; - 用
SCIPsetSolVal将临时数组中的值赋值给部分解对应的原变量,同时为新变量设置一个合理的初始值(比如0或业务相关的猜测值); - 最后调用
SCIPaddSolFree将这个部分解作为初始猜测加入SCIP。
这种方式避开了问题状态转换带来的解失效问题,逻辑更清晰,也更稳定。
内容的提问来源于stack exchange,提问作者Arseniy Spiridonov

