这个问题是关于 python 包约束(参见 http://labix.org/python-constraint ),特别是内置的“AllEqualConstraint”。在一个问题
涉及4个变量,我想强制执行前两个和
第二个两个相等,即:
p = Problem()
p.addVariables([1,2,3,4], [0,1])
p.addConstraint(AllEqualConstraint(), [1,2])
p.addConstraint(AllEqualConstraint(), [3,4])
我只有两个解决方案:
for sol in p.getSolutions():
print sol
> {1: 1, 2: 1, 3: 1, 4: 1}
> {1: 0, 2: 0, 3: 0, 4: 0}
我希望看到四个,即:
> {1: 1, 2: 1, 3: 1, 4: 1}
> {1: 1, 2: 1, 3: 0, 4: 0}
> {1: 0, 2: 0, 3: 1, 4: 1}
> {1: 0, 2: 0, 3: 0, 4: 0}
我的问题是:任何人都可以确认这是包打算计算的内容以及
背后的道理是什么?
Ps:我已经联系了这个包的作者,但还没有得到回复。我知道这个包是相当有名的,并且之前在 StackOverflow 上也有过关于它的问题。
回复 LVC:
约束确实 而不是 总是将约束应用于所有变量:
p = Problem()
p.addVariables([1,2,3], [0,1])
p.addConstraint(AllEqualConstraint(), [1,2])
给
> {1: 1, 2: 1, 3: 1}
> {1: 1, 2: 1, 3: 0}
> {1: 0, 2: 0, 3: 1}
> {1: 0, 2: 0, 3: 0}
正如预期的那样。如果
AllEqualConstraint
不尊重变量,它将非常有限。 最佳答案
模块的 source code 包含它如何执行 AllEqualConstraint
:
def __call__(self, variables, domains, assignments, forwardcheck=False,
_unassigned=Unassigned):
singlevalue = _unassigned
for value in assignments.values():
if singlevalue is _unassigned:
singlevalue = value
elif value != singlevalue:
return False
在每个
Solver
中调用它的代码执行以下操作:for constraint, variables in vconstraints[variable]:
if not constraint(variables, domains, assignments,
pushdomains):
# Value is not good.
break
assignments
包含所有变量的所有赋值,而不仅仅是受约束影响的变量。这意味着 AllEqualConstraint
不关心您放入 addConstraint
中的变量 - 它始终测试潜在解决方案中的所有变量是否相等,这就是为什么您会遗漏两个并非如此的解决方案。AllEqualConstraint
查看 variables
参数的唯一时间是在 forwardcheck
为真值的情况下调用它。在这种情况下,它会这样做:if forwardcheck and singlevalue is not _unassigned:
for variable in variables:
if variable not in assignments:
domain = domains[variable]
if singlevalue not in domain:
return False
for value in domain[:]:
if value != singlevalue:
domain.hideValue(value)
但是所提供的求解器似乎都没有使用默认值以外的任何
forwardcheck
值调用约束 - 在 AllEqualConstraint
的情况下是 False
。因此,您必须指定自己的手动约束 - 但这并不太难,因为它们可以只是采用适当数量的变量的函数(它被包装在
FunctionConstraint
中,因此您无需关心传递给 Constraint.__call__
的所有其他内容)。因此,您想要的约束是一个函数,它接受两个变量,并返回它们是否相等。
operator.eq
非常符合要求:p.addConstraint(operator.eq, [1, 2])
p.addConstraint(operator.eq, [3, 4])
应该给你你正在寻找的结果。
因此,将此扩展到两个以上的变量,您可以编写自己的函数:
def all_equal(a, b, c):
return a == b == c
或者,更一般地说:
def all_equal(*vars):
if not vars:
return True
return all(var == var[0] for var in vars)
关于python-constraint Allequal,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12177245/