
当使用 or-tools 调用 scip 求解混合整数规划(mip)问题时,若日志显示 presolve 持续多轮后无后续进展(如未进入主求解循环),极可能源于 scip 内部 presolve 死锁、模型结构缺陷或 or-tools 封装层对 scip 状态监听的局限性。
当使用 or-tools 调用 scip 求解混合整数规划(mip)问题时,若日志显示 presolve 持续多轮后无后续进展(如未进入主求解循环),极可能源于 scip 内部 presolve 死锁、模型结构缺陷或 or-tools 封装层对 scip 状态监听的局限性。
在 OR-Tools 中启用 solver.EnableOutput() 后,若终端长时间停留在类似以下 presolve 日志且无任何后续输出(如 presolved problem has ... 或分支定界表头),说明求解流程已实质性停滞:
(round 242, fast) 882 del vars, 1837 del conss, ... presolving (243 rounds: 243 fast, 53 medium, 53 exhaustive): 883 deleted vars, 1837 deleted constraints, ... 0 implications, 0 cliques
这并非 OR-Tools 本身的 Bug,而是其对底层 SCIP 的调用受限于接口抽象层级——OR-Tools 通过 C++ API 封装 SCIP,但无法完全暴露或干预 SCIP 内部 presolve 的线程状态、超时机制与异常恢复逻辑。尤其当 presolve 过程因数值不稳定、冗余约束爆炸或隐式对称性触发低效启发式时,原生 SCIP 可能陷入高复杂度简化循环,而 OR-Tools 默认不设置 presolve 超时,亦无法中断该阶段。
✅ 推荐诊断与解决路径如下:
-
导出模型,独立验证 SCIP 行为
首先将问题导出为标准 MPS 文件,绕过 OR-Tools 封装,直接使用官方 SCIP 二进制运行:# Python: 使用 OR-Tools 导出 MPS from ortools.linear_solver import pywraplp solver = pywraplp.Solver.CreateSolver('SCIP') # ... 构建你的模型(省略) solver.ExportModelAsMpsFormat('/tmp/problem.mps') # 注意:部分版本需启用 write_mps然后在命令行执行(确保已安装 SCIP Optimization Suite):
scip -f /tmp/problem.mps -l scip_log.txt
✅ 若原生 SCIP 同样卡住 → 问题根源在模型本身或 SCIP 版本缺陷;
❌ 若原生 SCIP 快速完成 presolve 并进入求解 → 则为 OR-Tools 与 SCIP 的集成兼容性问题(如 ABI 不匹配、编译选项差异),需升级 OR-Tools 或切换 SCIP 构建方式。 -
主动约束 presolve 行为(OR-Tools 内)
在创建求解器后,通过 SetSolverSpecificParametersAsString 传递 SCIP 参数,限制 presolve 强度与耗时:solver = pywraplp.Solver.CreateSolver('SCIP') # 关键参数:禁用高开销 presolve 步骤 params = ( "presolving/maxrounds = 50 " # 限制最大轮数(默认 -1 = 自适应) "presolving/maxrestarts = 0 " # 禁用 presolve 重启(易致死锁) "presolving/symmetry = off " # 关闭对称性检测(避免 SYM=none 报错干扰) "limits/time = 300 " # 全局超时 5 分钟(含 presolve) ) solver.SetSolverSpecificParametersAsString(params) -
模型层面优化建议
- 检查是否存在大量近似相等的约束(如 x ≤ 1.0000001 与 x ≤ 1.0 并存),导致 presolve 陷入边界微调循环;
- 移除冗余变量:对仅参与单个约束且系数为 ±1 的变量,手动消元;
- 避免大 M 法引入的弱松弛:改用指示约束(AddLinearConstraint + OnlyEnforceIf)或分段线性建模。
⚠️ 注意事项:
- OR-Tools 当前(v9.8+)捆绑的 SCIP 版本通常较旧(如 SCIP 8.x),而 presolve 死锁在 SCIP 9.x 中已有多个修复(见 SCIP Issue #327)。强烈建议优先尝试最新版独立 SCIP;
- 不要依赖 solver.TimeLimit() —— 它仅作用于主求解阶段,对 presolve 无效;必须使用 limits/time 等 SCIP 原生命令;
- 若问题规模小(
综上,SCIP 卡在 presolve 是典型的“黑盒阻塞”现象。根本解法不是等待,而是分层隔离:用 MPS + 原生 SCIP 定位归属,再通过参数调控与建模重构破局。 工程实践中,80% 的此类问题可通过关闭 maxrestarts 与设 maxrounds=30 立即缓解,剩余则需回归模型健康度审查。










