说我有约束:x < 2
,x > 3
和x > 5
,如何获得z3来产生 minimum (最小)的解决方案,例如x = [1, 6]
?
我想我可以使用Or
来实现它,并为每个求解阻塞已求解的条件,但这并不能保证它将产生最小的集合。
我的另一种解决方案是分别解决每个条件并收集尽可能多的结果,并具有一种算法来选择每个条件的重叠结果。
有什么主意吗?
答案 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
如果一次不能解决所有组合问题,请转到下面的级别。如果有两个条件的解决方案,则查看第三个条件的解决方案。您可以为此制定一个算法。