Docplex中add_sos1方法运行过慢的原因排查求助
问题分析与解决方案
为什么add_sos1运行缓慢?
这不是bug,是大规模SOS1约束的正常性能表现。如果Yijpt的规模较大(比如数千甚至上万条),你逐个调用add_sos1会生成大量独立的SOS1集合,每个集合包含2个变量。求解器处理SOS1约束的开销远高于普通线性约束,尤其是当集合数量爆炸时,会导致预处理和约束加载速度骤降。
更关键的问题:你的线性化思路错误
你试图用TV + TVP表示|0.5 - Y|,但当前的约束和目标设置完全偏离了初衷:
- 约束
TV - TVP = 0.5 - Y加上目标最大化TV + TVP,并不能保证TV + TVP等于|0.5 - Y|。求解器会尽可能让TV和TVP同时取最大值,使得TV + TVP远大于实际的绝对值,完全达不到“推动解向整数值靠拢”的目的。 - 你根本不需要用SOS1,直接用普通线性约束就能准确实现目标。
正确的实现方式
要最大化|0.5 - Y|,最直接高效的线性化方法是引入辅助变量表示绝对值,添加两个线性约束:
# 为每个Yijpt创建辅助变量Z,用于表示|0.5 - Yijpt| Zijpt = MODEL.continuous_var_dict(Yijpt.keys(), name='Z', lb=0) # 目标函数:最大化所有Z的和 MODEL.set_objective(sum(Zijpt[k] for k in Yijpt.keys()), sense='max') # 添加绝对值的线性约束 for k in Yijpt.keys(): Y = Yijpt[k] Z = Zijpt[k] MODEL.add_constraint(Z >= 0.5 - Y) MODEL.add_constraint(Z >= Y - 0.5)
补充说明
如果你坚持要用TV/TVP变量(不推荐),必须修正目标和约束:
- 目标应该是让
TV + TVP等于|0.5 - Y|,而非最大化TV + TVP,同时用SOS1约束TV和TVP不同时非零。但这种方式既复杂又低效,远不如上面的线性约束方案。
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

