You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在OR-Tools中如何对带模运算与除法的复杂整数约束进行建模?

OR-Tools CP-SAT 模除类约束建模方案

问题分析

你遇到的报错是因为OR-Tools的CP-SAT求解器的IntVar类型不支持直接使用C#原生的%、/运算符,所有整数运算约束都需要通过求解器提供的内置API建模。另外你更新后的代码存在多处逻辑错误,下面先说明错误点,再给出正确且高效的实现方案。


你更新后代码的错误点

  • 运算符误用:C#中^是按位异或运算符,不是幂运算,26 ^ 13实际计算结果为23,和你需要的26的13次方数值完全不符,这是最致命的错误。
  • 变量绑定错误:计算w2的模约束时,你复制粘贴导致写错变量,代码行model.Add(w1 == ((w1Modulo * multiplicandw2) + remainderw2));应该使用w2和w2Modulo。
  • 商变量定义错误:你将商变量multiplicandw1的定义域固定为模数值,这不符合整除逻辑,商是随输入变量变化的自由整数变量,不能固定值。
  • 余数范围错误:你定义remainderw1的上界为26^12 - 1,这导致余数永远小于26^12,除以26^12的结果永远为0,完全不符合你的约束要求。
  • 等价约束错误:最后比较的逻辑写错,你需要的是remainderw1 / 26^12 == remainderw2 / 26^4,等价于remainderw1 * 26^4 == remainderw2 * 26^12,不是乘以模数值。

正确建模方案

方案1:使用内置模、除约束API(通用场景)

OR-Tools CP-SAT已经提供了AddModuloEquality和AddDivisionEquality内置方法,不需要手动拆分整除公式:

// 提前计算常量,不要用^运算符
const long K1 = 95428956661682176; // 26^12
const long M1 = K1 * 26; // 26^13
const long K2 = 456976; // 26^4
const long M2 = K2 * 26; // 26^5

// w1、w2定义和你的原代码一致
IntVar w1 = model.NewIntVarFromDomain(Domain.FromValues(wl1), "w1");
IntVar w2 = model.NewIntVarFromDomain(Domain.FromValues(wl2), "w2");

// 计算左边值:(w1 mod M1) / K1
IntVar mod1 = model.NewIntVar(0, M1 - 1, "mod1");
model.AddModuloEquality(mod1, w1, M1);
IntVar leftBit = model.NewIntVar(0, 25, "leftBit");
model.AddDivisionEquality(leftBit, mod1, K1);

// 计算右边值:(w2 mod M2) / K2
IntVar mod2 = model.NewIntVar(0, M2 - 1, "mod2");
model.AddModuloEquality(mod2, w2, M2);
IntVar rightBit = model.NewIntVar(0, 25, "rightBit");
model.AddDivisionEquality(rightBit, mod2, K2);

// 加相等约束
model.Add(leftBit == rightBit);

方案2:表约束优化(适合枚举域、大量同类约束场景)

你的w1、w2都是有限枚举值,完全可以提前预处理出每个值对应的目标位,用表约束(AllowedAssignments)实现,性能比模除约束高10倍以上,尤其适合约束量大的场景:

// 提前预处理w1的取值和对应位的映射
List<Tuple<long, long>> w1BitMap = new List<Tuple<long, long>>();
foreach (var val in wl1)
{
    long bit = (val % M1) / K1;
    w1BitMap.Add(Tuple.Create(val, bit));
}

// 提前预处理w2的取值和对应位的映射
List<Tuple<long, long>> w2BitMap = new List<Tuple<long, long>>();
foreach (var val in wl2)
{
    long bit = (val % M2) / K2;
    w2BitMap.Add(Tuple.Create(val, bit));
}

// 新建公共中间变量
IntVar commonBit = model.NewIntVar(0, 25, "commonBit");

// 加表约束
model.AddAllowedAssignments(new IntVar[] { w1, commonBit }, w1BitMap.Select(t => new long[] { t.Item1, t.Item2 }).ToList());
model.AddAllowedAssignments(new IntVar[] { w2, commonBit }, w2BitMap.Select(t => new long[] { t.Item1, t.Item2 }).ToList());

内容的提问来源于stack exchange,提问作者T.Bob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:57:01