为什么Z3Py无法提供所有可能的解决方案

时间:2018-11-05 21:12:33

标签: python z3py sat

我遇到了一个问题,其中Z3Py并未枚举给定布尔条款的所有可能解决方案。我想知道是否有人知道为什么会这样。

这是我用于Z3Py的代码。有5个布尔值:1 2 3 4和5。

from z3 import *

a,b,c,d,e = Bools('1 2 3 4 5')
solver = Solver()
solver.add(Or(Not(a), Not(b)))
solver.add(Or(Not(b), Not(c)))
solver.add(Or(Not(c), Not(d)))
solver.add(Or(Not(d), Not(e)))

while solver.check() == sat:
    model = solver.model()
    block = []
    for declaration in model:
        constant = declaration()
        block.append(constant != model[declaration])
    solver.append(Or(block))
    solution = []
    for val in model:
        if is_true(model[val]):
            solution.append(str(val()))
        else:
            solution.append('-' + str(val()))
    solution.sort()
    print(solution)

这将产生以下模型:

['-1', '-2', '-3', '-4', '-5']
['-2', '-3', '-5', '1']
['-2', '-3', '-4', '1', '5']
['-2', '-4', '3', '5']
['-2', '-4', '-5', '3']
['-1', '-3', '-4', '-5', '2']
['-1', '-3', '-4', '2', '5']
['-1', '-2', '-3', '-4', '5']
['-1', '-2', '-3', '-5', '4']
['-1', '-3', '-5', '2', '4']

如果我使用带有以下代码的Pycosat运行相同的子句:

import pycosat
clauses = [(-1, -2), (-2, -3), (-3, -4), (-4, -5)]
for solution in pycosat.itersolve(clauses):
    print(solution)

我得到那些结果:

[-1, -2, -3, -4, -5]
[-1, -2, -3, -4, 5]
[-1, -2, -3, 4, -5]
[-1, -2, 3, -4, -5]
[-1, -2, 3, -4, 5]
[-1, 2, -3, -4, -5]
[-1, 2, -3, -4, 5]
[-1, 2, -3, 4, -5]
[1, -2, -3, 4, -5]
[1, -2, -3, -4, -5]
[1, -2, -3, -4, 5]
[1, -2, 3, -4, -5]
[1, -2, 3, -4, 5]
因此,Z3Py根据Pycosat的结果错过了3种可能的解决方案。这些是:

[1, -2, 3, -4, 5]
[1, -2, -3, 4, -5]
[1, -2, 3, -4, -5]

我知道这些是不同的求解器,但是基于用于它们的相同子句,我希望结果匹配。谁知道在这种情况下Z3Py为什么会错过这些解决方案? 另一件事是,并非Z3Py中的所有解决方案都包含所有定义的变量。

2 个答案:

答案 0 :(得分:1)

  

另一件事是,并非Z3Py中的所有解决方案都包含所有已定义的变量。

这意味着未提及的变量不会影响结果。因此,将['-2', '-4', '3', '5']作为解决方案等同于同时拥有['1', '-2', '-4', '3', '5']['-1', '-2', '-4', '3', '5']

如果在比较解决方案时考虑到这一点,则两个求解器提供的解决方案集是等效的。

答案 1 :(得分:1)

请注意,模型将只包含对在sat结果中重要的变量的赋值。任何无关紧要的变量都不会明确分配。为避免此问题,请循环遍历您域中的变量,并将参数model_completion=True用于eval方法,如下所示:

from z3 import *

a,b,c,d,e = Bools('1 2 3 4 5')
solver = Solver()
solver.add(Or(Not(a), Not(b)))
solver.add(Or(Not(b), Not(c)))
solver.add(Or(Not(c), Not(d)))
solver.add(Or(Not(d), Not(e)))

while solver.check() == sat:
    model = solver.model()
    block = []
    solution = []

    for var in [a, b, c, d, e]:
        v = model.eval(var, model_completion=True)
        block.append(var != v)
        solution.append(str(var) if is_true(v) else '-' + str(var))

    solver.add(Or(block))
    solution.sort()
    print(solution)

此打印:

['-1', '-2', '-3', '-4', '-5']
['-2', '-3', '-4', '-5', '1']
['-2', '-3', '-5', '1', '4']
['-1', '-2', '-3', '-5', '4']
['-1', '-2', '-3', '-4', '5']
['-1', '-2', '-4', '3', '5']
['-2', '-4', '-5', '1', '3']
['-2', '-4', '1', '3', '5']
['-2', '-3', '-4', '1', '5']
['-1', '-3', '-4', '2', '5']
['-1', '-3', '-4', '-5', '2']
['-1', '-2', '-4', '-5', '3']
['-1', '-3', '-5', '2', '4']

我相信这是您要寻找的。