Python (Z3Py)检查方程的所有解
在Z3Py中,如何检查给定约束的方程是否只有一个解Python (Z3Py)检查方程的所有解,python,z3,z3py,Python,Z3,Z3py,在Z3Py中,如何检查给定约束的方程是否只有一个解 如果有多个解决方案,如何枚举它们?您可以通过添加阻止Z3返回的模型的新约束来实现这一点。 例如,假设在Z3返回的模型中,我们有x=0和y=1。然后,我们可以通过添加约束或(x!=0,y!=1)来阻止该模型。 下面的脚本实现了这个技巧。 您可以在以下网站在线试用: 请注意,下面的脚本有几个限制。输入公式不能包含未解释的函数、数组或未解释的排序 from z3 import * # Return the first "M" models of f
如果有多个解决方案,如何枚举它们?您可以通过添加阻止Z3返回的模型的新约束来实现这一点。 例如,假设在Z3返回的模型中,我们有
x=0
和y=1
。然后,我们可以通过添加约束或(x!=0,y!=1)
来阻止该模型。
下面的脚本实现了这个技巧。
您可以在以下网站在线试用:
请注意,下面的脚本有几个限制。输入公式不能包含未解释的函数、数组或未解释的排序
from z3 import *
# Return the first "M" models of formula list of formulas F
def get_models(F, M):
result = []
s = Solver()
s.add(F)
while len(result) < M and s.check() == sat:
m = s.model()
result.append(m)
# Create a new constraint the blocks the current model
block = []
for d in m:
# d is a declaration
if d.arity() > 0:
raise Z3Exception("uninterpreted functions are not supported")
# create a constant from declaration
c = d()
if is_array(c) or c.sort().kind() == Z3_UNINTERPRETED_SORT:
raise Z3Exception("arrays and uninterpreted sorts are not supported")
block.append(c != m[d])
s.add(Or(block))
return result
# Return True if F has exactly one model.
def exactly_one_model(F):
return len(get_models(F, 2)) == 1
x, y = Ints('x y')
s = Solver()
F = [x >= 0, x <= 1, y >= 0, y <= 2, y == 2*x]
print get_models(F, 10)
print exactly_one_model(F)
print exactly_one_model([x >= 0, x <= 1, y >= 0, y <= 2, 2*y == x])
# Demonstrate unsupported features
try:
a = Array('a', IntSort(), IntSort())
b = Array('b', IntSort(), IntSort())
print get_models(a==b, 10)
except Z3Exception as ex:
print "Error: ", ex
try:
f = Function('f', IntSort(), IntSort())
print get_models(f(x) == x, 10)
except Z3Exception as ex:
print "Error: ", ex
从z3导入*
#返回公式F列表中公式的第一个“M”模型
def get_型号(F、M):
结果=[]
s=解算器()
s、 加(F)
而len(result) F=[x>=0,x=0,y=0,x=0,y下面的python函数是包含常量和函数的公式的模型生成器
import itertools
from z3 import *
def models(formula, max=10):
" a generator of up to max models "
solver = Solver()
solver.add(formula)
count = 0
while count<max or max==0:
count += 1
if solver.check() == sat:
model = solver.model()
yield model
# exclude this model
block = []
for z3_decl in model: # FuncDeclRef
arg_domains = []
for i in range(z3_decl.arity()):
domain, arg_domain = z3_decl.domain(i), []
for j in range(domain.num_constructors()):
arg_domain.append( domain.constructor(j) () )
arg_domains.append(arg_domain)
for args in itertools.product(*arg_domains):
block.append(z3_decl(*args) != model.eval(z3_decl(*args)))
solver.add(Or(block))
x, y = Ints('x y')
F = [x >= 0, x <= 1, y >= 0, y <= 2, y == 2*x]
for m in models(F):
print(m)
导入itertools
从z3进口*
def型号(公式,最大值=10):
“最大型号的发电机”
解算器=解算器()
求解器。添加(公式)
计数=0
当count=0,x=0,y
def所有smt,初始术语:
def块_术语(s、m、t):
s、 加(t!=m.eval(t))
def固定术语(s、m、t):
s、 加(t==m.eval(t))
定义所有信息(条款):
如果sat==s.check():
m=s.模型()
产量m
对于范围内的i(len(术语)):
s、 推
块_项(s、m、项[i])
对于范围(i)中的j:
固定期限(s、m、期限[j])
对于所有记录中的m(条款[i:]):
产量m
s、 流行音乐()
对于所有记录中的m(列表(初始术语)):
产量m
从莱昂纳多自己的答案来看,这确实表现得更好(考虑到他的答案相当陈旧)
start\u time=time.time()
v=[BitVec(f'v{i}',3)表示范围(6)内的i]
模型=获取模型([总和(v)==0],8**5)
打印(time.time()-开始时间)
#211.6482105255127s
start\u time=time.time()
s=解算器()
v=[BitVec(f'v{i}',3)表示范围(6)内的i]
s、 加(和(v)==0)
型号=列表(所有型号)
打印(time.time()-开始时间)
#13.375828742980957s
据我观察,将搜索空间拆分为不相交的模型会产生巨大的差异我还想问,Z3的SMT语言扩展中是否也可能出现这种情况?不,不可能。但是,我认为在SMT 2.0前端添加此命令是一个好主意。您是否可以添加一条注释来解释为什么会出现未解释的函数和数组不支持使用这种方法吗?这是一个偶然的限制(数据结构不是ExprRefs或其他什么)还是一个更基本的限制?很好的发现!在我的实验中,这确实快了很多。