z3查找满足多个冲突约束的最小组合

时间:2020-09-15 12:38:34

标签: python z3

说我有约束:x < 2x > 3x > 5,如何获得z3来产生 minimum (最小)的解决方案,例如x = [1, 6]

我想我可以使用Or来实现它,并为每个求解阻塞已求解的条件,但这并不能保证它将产生最小的集合。

我的另一种解决方案是分别解决每个条件并收集尽可能多的结果,并具有一种算法来选择每个条件的重叠结果。

有什么主意吗?

2 个答案:

答案 0 :(得分:2)

这种“跟踪”约束经常出现。尽管可能有多种解决方案,但我认为最好的解决方案是显式添加跟踪变量,并进行迭代,直到满足所有约束为止。为此,您应该使用优化求解器,以使每次调用中释放的约束数量最大化。这样,您可以确保解决方案的数量保持最少。

基于此策略,我将为每个约束创建一个跟踪器变量pN,并将它们与含义配对。然后,我最大化应满足的pN的数量。这是一种可能的编码:

from z3 import *

x = Int('x')

p1, p2, p3 = Bools('p1 p2 p3')
constraints = [(p1, x < 2), (p2, x > 3), (p3, x > 5)]

solutions = []
while constraints:
    o = Optimize()

    s = 0
    for (tracker, condition) in constraints:
        o.add(Implies(tracker, condition))
        s = s + If(tracker, 1, 0)
    o.maximize(s)

    remaining = []
    r = o.check()
    if r == sat:
        m = o.model()
        solutions.append(m[x])
        print("Candidate: %s" % m[x])
        for (tracker, condition) in constraints:
            if(m[tracker]):
                print("  Constraint: %s satisfied, skipping." % condition.sexpr())
            else:
                print("  Constraint: %s is not yet satisfied, adding." % condition.sexpr())
                remaining.append((tracker, condition))
    else:
        print("Call returned: %s" % r)
        exit(-1)

    constraints = remaining

print("Solution: %s" % solutions)

运行时,将打印:

Candidate: 6
  Constraint: (< x 2) is not yet satisfied, adding.
  Constraint: (> x 3) satisfied, skipping.
  Constraint: (> x 5) satisfied, skipping.
Candidate: 0
  Constraint: (< x 2) satisfied, skipping.
Solution: [6, 0]

因此,这将计算解决方案[6, 0]。您最初想要[1, 6],但我认为这也是一个有效的解决方案。

如果您也想获得更严格的界限,还可以向优化求解器添加条件(通过最小化/最大化调用)。但是,这很可能会遇到问题:例如,对于您的原始约束集,没有{/ {1}}的最小值/最大值无法唯一满足它们,因此您可能会遇到优化器将失败的情况。如果您知道所有变量都是有界的,则可以通过该路线。否则,您可以尝试调用优化器,如果它没有返回固定的结果,请像上面一样处理x调用的结果。当然,所有这些都取决于您具有的特定约束,但是与z3无关。

答案 1 :(得分:0)

我认为x <2,x> 3和x> 5没有解决方案。您可以找到第一个解决方案,然后将其添加到条件中。 例如

from z3 import *
solver = Solver()
x = Int('x')

constraints = [
    x < 5
]

for i in constraints:
    solver.add(i)
print(solver.check())
while solver.check() == sat:
    print(solver.model()[x])
    solver.add(x < solver.model()[x])

Output:
sat
4
0
-1
-2
-3
-4
-5
-6
-7
....
-to minus infinity

第二个解决方案

 from z3 import *
import itertools
solver = Solver()
x = BitVec('x', 64)

combinations = [
    x < 2,
    x > 3,
    x > 5
]

#I create a list of all possible combinations of conditions
stuff = [0, 1, 2]
conditionLst = []
for L in range(0, len(stuff)+1):
    for subset in itertools.combinations(stuff, L):
        conditionLst.append(subset)
print(conditionLst)


#for every combination I am looking for solutions
for cond in conditionLst:
    solver = Solver()
    for i in cond:
        solver.add(combinations[i])
    solver.check()
    if solver.check() == sat:
        for j in cond:
            print(combinations[j], end=", ")
        print(solver.model())
    elif solver.check() == unsat:
        for j in cond:
            print(combinations[j], end=", ")
        print(solver.check())
    del solver


x < 2, [x = 1]
x > 3, [x = 4]
x > 5, [x = 6]
x < 2, x > 3, unsat
x < 2, x > 5, unsat
x > 3, x > 5, [x = 6]
x < 2, x > 3, x > 5, unsat

如果一次不能解决所有组合问题,请转到下面的级别。如果有两个条件的解决方案,则查看第三个条件的解决方案。您可以为此制定一个算法。

相关问题