如果IntVar []中存在“互惠”分配,我正在尝试分配成本。这是我在较旧的ConstraintSolver中完成此操作的方式...
IntVar[] assignments = solver.MakeIntVarArray(size, 0, size-1, "assignments");
var cost = Enumerable.Range(0, size)
.Select(i => 999 * (assignments.Element(assignments[i]) == i))
.ToArray()
.ToSum()
.Var();
var objective = cost.Minimize(1);
现在,我尝试在CpSolver
扩展名不存在的Google.OrTools.Sat
中使用较新的.Element
(我认为是有充分理由的)。我已经设法使用四个IntVars []使它“工作”,但我怀疑这只是我的一次重大建模失败。
foreach (var i in Enumerable.Range(0, size))
{
model.AddElement(assignments[i], assignments, reciprocals[i]);
model.Add(reciprocals[i] == i).OnlyEnforceIf(reciprocalBools[i]);
model.Add(reciprocals[i] != i).OnlyEnforceIf(reciprocalBools[i].Not());
model.Add(costs[i] == 999).OnlyEnforceIf(reciprocalBools[i]);
model.Add(costs[i] == 0).OnlyEnforceIf(reciprocalBools[i].Not());
}
model.Minimize(costs.Sum());
根据我的测试,上述内容在功能上似乎是正确的,但是随着size
的变大,我的测试应用程序的SAT版本比CS版本差几个数量级。
任何建议将不胜感激。
答案 0 :(得分:1)
这是一个更好的版本
foreach (var i in Enumerable.Range(0, size))
{
model.AddElement(assignments[i], assignments, reciprocals[i]);
model.Add(reciprocals[i] == i).OnlyEnforceIf(reciprocalBools[i]);
model.Add(reciprocals[i] != i).OnlyEnforceIf(reciprocalBools[i].Not());
}
model.Minimize(999 * LinearExpr.Sum(reciprocalBools));
我们还有一个逆约束(model.AddInverseConstraint(x_array, y_array)
)
强制
x_array[i] == j <=> y_array[j] == i
我还是想知道您是否需要所有这些东西。
如果xi = {xi_1, .., xi_n}
(映射到布尔变量数组)
reciprocalBools[i] is true
,如果exists j, such that (xi_j && xj_i) is true
因此,您只需要计算成对的(xi_j && xj_i)
对。
这并不简单。
给定i和j,i!= j
Literal implied = model.newBoolVar("");
model.addBoolOr(new Literal[] {xi_j.not(), xj_i.not(), implied});
model.addImplication(implied, xi_j);
model.addImplication(implied, xj_i);
现在,您有implied <=> xi_j && xj_i
。您可以计算这些implied
变量。
如果i == j,则不要创建implied
变量,不要添加3布尔约束,并直接使用xi_i。