PySCIPOpt获取LP对偶解的参数配置及获取方法咨询
是否必须关闭预求解、禁用传播才能获取对偶解?
答案是完全不需要。
网上流传的「必须关闭预求解、禁用传播才能拿对偶」的说法,本质是早年SCIP 3.x及更早版本的遗留问题:当时版本的求解后回代(postsolve)逻辑不会把预求解阶段简化、变形后的问题对偶值映射回用户最初建的原始模型空间,用户拿到的是变形后内部模型的对偶,和自己加的原始约束根本对不上,才会出数值错误、符号不对、匹配错位的问题。
从SCIP 4.0版本及配套的PySCIPOpt开始,默认参数下求解完成、达到最优状态后,求解器会自动完成postsolve全流程,把简化问题的对偶解准确映射到原始模型的约束、变量空间,不需要提前禁用预求解和传播功能。
要注意一个核心前提:这个结论仅针对纯线性规划(LP,无任何离散类型变量),混合整数规划(MIP)本身不存在全局定义的对偶解,无论怎么调参数都无法拿到有严格理论意义的原问题全局对偶值。
可稳定获取对偶解的宽松参数设置
如果遇到默认参数下对偶值获取异常的情况,不需要直接把预求解、传播全关,优先调整以下参数即可,对求解效率的影响远小于完全关闭预求解:
- 保持
presolving/maxrounds为默认值(-1,即自动选择预求解轮数),仅需确认misc/calcsols参数为开启状态(默认值为1,即开启),保证求解结束后自动执行完整的解回代流程。 - 不需要全局关闭约束传播,默认传播规则不会破坏对偶解的映射关系;仅当你自定义了会不可逆修改问题结构的激进传播插件时,才需要调整对应传播插件的优先级。
- 如果默认设置下对偶值存在映射偏差,仅需将
presolving/donotmultaggr参数设为1(禁用多约束聚合的预求解规则)即可,其余预求解、传播功能保持默认开启,求解效率损失极小。 - 必须等求解器完全返回最优状态(即
model.getStatus() == 'optimal')之后再取对偶值,不要在求解回调、求解中途提前取值,此时postsolve流程还未执行,拿到的是中间变换后问题的对偶,和原问题不匹配。 - 只有上述调整都无法解决对偶值异常的极端情况,才需要把
presolving/maxrounds设为0完全关闭预求解,这是兜底方案,不是必须的首选设置。
是否支持直接获取完整对偶解向量
支持,不需要逐一对每个约束调用getDualsolLinear方法:
在PySCIPOpt 4.0及以上版本中,Model类提供了getDuals()方法,你只需要把要获取对偶值的约束按需要的顺序存入一个列表(推荐建模时就把所有自己添加的业务线性约束存在自定义列表里),求解完成后直接调用dual_vec = model.getDuals(conss),就能得到和输入约束列表顺序完全一一对应的对偶值序列,直接构成完整的对偶解向量。
注意:
getDualsolLinear仅能作用于线性约束,而getDuals()会自动适配约束类型,纯LP场景下所有线性约束的对偶值都可以通过该方法批量获取,效率远高于循环逐个调用单约束取对偶的接口。如果建模时没有提前存约束列表,也可以通过model.getConss()拿到模型内的所有约束再传给getDuals(),但这个方法返回的列表会包含SCIP自动添加的辅助约束,和你自己添加的业务约束顺序不对应,需要自行做匹配过滤。
内容的提问来源于stack exchange,提问作者optimal-br

