这个问题是关于 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/

10-12 23:58