简体   繁体   English

使用 z3py 中的 Optimize() 查找所有最佳解决方案

[英]Find all optimal solutions with Optimize() from z3py

z3 can solve optimisation problems using z3.Optimize . z3可以使用z3.Optimize解决优化问题。 My goal is to apply it in the following way: Given a Boolean formula of propositional logic and a set of constraints, find all models that optimise the constraints, ie fulfil as many as possible.我的目标是以下列方式应用它:给定命题逻辑的 Boolean 公式和一组约束,找到所有优化约束的模型,即尽可能多地满足。 My ultimate goal is to select one of these models randomly.我的最终目标是随机选择其中一种型号 select 。

Minimal example: Given the formula Or(x,y) and constraints Not(x) and Not(y) , find the solutions [x: True, y: False] and [x: False, y: True] .最小示例:给定公式Or(x,y)和约束Not(x)Not(y) ,找到解[x: True, y: False][x: False, y: True]

While z3.Optimize.model() prints one optimal solution, it seems to be deterministic and to always print the solution [x: False, y: True] :虽然z3.Optimize.model()打印一个最佳解决方案,但它似乎是确定性的并且总是打印解决方案[x: False, y: True]

from z3 import *

x, y = Bools('x y')
s = Optimize()
s.add(Or(x,y))
s.add_soft(Not(x), weight="1")
s.add_soft(Not(y), weight="1")
s.check()
print(s.model())

When all_smt() provided by @alias is applied to this problem, list(all_smt(s, [x,y])) outputs:all_smt()应用于这个问题时, list(all_smt(s, [x,y]))输出:

[[x = False, y = True], [y = False, x = True], [y = True, x = True]]

So all_smt() finds all solutions, including the non-optimal [x: True, y: True] .所以all_smt()找到所有解决方案,包括非最优的[x: True, y: True]

What is the best way to find all optimal solutions?找到所有最佳解决方案的最佳方法是什么? Alternatively, is it possible to find an optimal solution in a random way without generating all optimal solutions first?或者,是否可以在不首先生成所有最优解的情况下以随机方式找到最优解?

It's not quite clear what you mean by "optimal" in this context.在这种情况下,您所说的“最佳”是什么意思并不十分清楚。 It appears you allow the soft-constraints to be violated, but at least one of them must hold?看来您允许违反软约束,但至少其中一个必须保持? (After all, ( [x=True, y=True] is a valid solution, violating both your soft-constraints; which you did allow by explicitly calling all_smt .) (毕竟, ( [x=True, y=True]是一个有效的解决方案,违反了您的两个软约束;您确实通过显式调用all_smt来允许。)

Assuming you are indeed looking for solutions that satisfy at least one of the soft-constraints, you should explicitly code that up and assert as a separate predicate.假设您确实在寻找满足至少一个软约束的解决方案,您应该明确地对其进行编码并将其断言为单独的谓词。 The easiest way to do this would be to use tracker variables:最简单的方法是使用跟踪器变量:

from z3 import *

def all_smt(s, initial_terms):
    def block_term(s, m, t):
        s.add(t != m.eval(t, model_completion=True))
    def fix_term(s, m, t):
        s.add(t == m.eval(t, model_completion=True))
    def all_smt_rec(terms):
        if sat == s.check():
           m = s.model()
           yield m
           for i in range(len(terms)):
               s.push()
               block_term(s, m, terms[i])
               for j in range(i):
                   fix_term(s, m, terms[j])
               yield from all_smt_rec(terms[i:])
               s.pop()
    yield from all_smt_rec(list(initial_terms))

x, y = Bools('x y')
s = Optimize()
s.set(priority='pareto')

s.add(Or(x,y))

p1, p2 = Bools('p1 p2')
s.add(Implies(p1, Not(x)))
s.add(Implies(p2, Not(y)))

asserted = If(p1, 1, 0) + If(p2, 1, 0)
s.add(asserted >= 1)
s.minimize(asserted)

print([[(x, m[x]), (y, m[y])] for m in all_smt(s, [x,y])])

Here, we use p1 and p2 to track whether the soft-constraints are asserted, and we minimize the number of soft-constraints via the variable asserted yet requiring it should at least be 1. When run, the above prints:在这里,我们使用p1p2来跟踪软约束是否被断言,并且我们通过asserted变量最小化软约束的数量,但要求它至少应该为 1。运行时,上面的打印结果:

[[(x, True), (y, False)], [(x, False), (y, True)]]

which seems to be what you wanted to achieve in the first place.这似乎是您首先想要实现的目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM