[英]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:在这里,我们使用p1
和p2
来跟踪软约束是否被断言,并且我们通过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.