请求排查CPLEX求和约束错误:二进制变量x求和约束问题
排查CPLEX中二进制变量x的求和约束错误
我帮你梳理下最后那条ctWorkOneShiftPerDay约束的问题,核心问题出在变量嵌套和逻辑范围上:
- 变量冲突导致逻辑偏离:你在
forall(w in worker, i in part, h in period)的外层循环里已经用了i作为遍历变量,结果内层求和又写了sum (i in part)——这会让CPLEX把内层的i当成全新的局部变量,等于给每个工人、每个零件、每个周期都重复计算了一次所有零件的x值之和,完全不符合你“每个工人每天只做一种零件”的需求。 - 逻辑范围错误:从约束名称能看出来,你想限制的是每个工人在单个周期内,最多只能分配到一种零件的工作,所以遍历范围应该是每个工人+每个周期,不需要把零件
i放到外层的forall里。
修正后的约束代码
把原约束调整成下面这样,就符合你的业务逻辑了:
ctWorkOneShiftPerDay: forall(w in worker, h in period) { sum (i in part) x[w, i, h] <= 1; }
额外的优化提示
顺便提一下ctworkHrperPeriod约束的小问题:
你现在写的是:
ctworkHrperPeriod: forall (w in worker,i in part, h in period) { workHr[w, h] >= 10.50 + 100000000 * (1 - x[w, i, h]); workHr[w, h] <= 10.50 - 100000000 * (1 - x[w, i, h]); }
这个写法等价于:当x[w,i,h] = 1时,workHr[w,h]必须等于10.50;但如果没修正前面的约束,一个工人在某天被分配到多个零件的话,这里会直接导致矛盾(要求workHr同时等于10.50多次,逻辑冲突)。修正完ctWorkOneShiftPerDay后,每个工人每天最多只有一个x[w,i,h]为1,这个约束就能正常生效了。
另外,建议把那个超大的M值100000000定义成一个常量,比如:
const float BIG_M = 1e8;
然后在约束里用BIG_M代替硬编码的数字,这样代码可读性更高,后续调整也更方便。
内容的提问来源于stack exchange,提问作者Khải Duy
相关产品推荐
相关产品推荐

