在Z3Py中,我需要使用标准语法term := const | var | f(t1,...,tn)
来检查某个词是否是一个术语。我已经编写了以下函数来确定但是我的方法来检查n-ary函数是否看起来不是最优的。
有没有更好的方法呢?这些实用程序函数is_term
,is_atom
,is_literal
等可以包含在Z3中。我将把它们放在contrib部分
CONNECTIVE_OPS = [Z3_OP_NOT,Z3_OP_AND,Z3_OP_OR,Z3_OP_IMPLIES,Z3_OP_IFF,Z3_OP_ITE]
REL_OPS = [Z3_OP_EQ,Z3_OP_LE,Z3_OP_LT,Z3_OP_GE,Z3_OP_GT]
def is_term(a):
"""
term := const | var | f(t1,...,tn)
"""
if is_const(a):
return True
else:
r = (is_app(a) and \
a.decl().kind() not in CONNECTIVE_OPS + REL_OPS and \
all(is_term(c) for c in a.children()))
return r
答案 0 :(得分:1)
功能合理,有几条评论:
这取决于您的规范中“var”的含义。 Z3的变量为de-Brujin指数。在z3py“is_var(a)”中有一个函数来检查“a”是否是变量索引。
还有另一个布尔连接词Z3_OP_XOR。
还有其他关系操作,例如比较位向量的操作。 这取决于你的意图和代码的用法,但你可以检查是否 表达式的排序是布尔值,如果确保头函数符号是 未解释的。
is_const(a)定义为return is_app(a)和a.num_args()== 0.所以is_const实际上是由默认情况处理的。
Z3因简化,解析或其他转换而创建的表达式可能包含许多共享子表达式。因此,直接递归下降可以在表达式的DAG大小中采用指数时间。您可以通过维护受访节点的哈希表来处理此问题。从Python中,您可以使用Z3_get_ast_id来检索表达式的唯一编号,并将其保存在集合中。只要术语不是垃圾收集,标识符就是唯一的 你应该将这样的一组保存为局部变量。
所以,有些东西:
def get_expr_id(e):
return Z3_get_ast_id(e.ctx.ref(), e.ast)
def is_term_aux(a, seen):
if get_expr_id(a) in seen:
return True
else:
seen[get_expr_id(a)] = True
r = (is_app(a) and \
a.decl().kind() not in CONNECTIVE_OPS + REL_OPS and \
all(is_term_aux(c, seen) for c in a.children()))
return r
def is_term(a):
return is_term_aux(a, {})
答案 1 :(得分:1)
一阶逻辑中使用的术语,原子和文字的“教科书”定义不能直接应用于Z3表达式。在Z3中,我们允许使用f(And(a, b)) > 0
和f(ForAll([x], g(x) == 0))
等表达式,其中f
是从布尔到整数的函数。这种扩展不会增加表现力,但在编写问题时它们非常方便。 SMT 2.0标准还允许使用“term”if-then-else
表达式。这是另一个允许我们在“术语”中嵌套“公式”的功能。示例:g(If(And(a, b), 1, 0))
。
当实现操作Z3表达式的过程时,我们有时需要区分布尔表达式和非布尔表达式。在这种情况下,“term”只是一个没有布尔排序的表达式。
def is_term(a):
return not is_bool(a)
在其他情况下,我们希望以特殊方式处理布尔连接词(And
,Or
,...)。例如,我们正在定义CNF翻译器。在这种情况下,我们将“atom”定义为不是量词的任何布尔表达式,是(自由)变量或不是布尔连接词之一的应用程序。
def is_atom(a):
return is_bool(a) and (is_var(a) or (is_app(a) and a.decl().kind() not in CONNECTIVE_OPS))
在我们定义一个原子之后,一个文字可以定义为:
def is_literal(a):
return is_atom(a) or (is_not(a) and is_atom(a.arg(0)))
以下示例演示了这些功能(也可在rise4fun在线获得):
x = Int('x')
p, q = Bools('p q')
f = Function('f', IntSort(), BoolSort())
g = Function('g', IntSort(), IntSort())
print is_literal(Not(x > 0))
print is_literal(f(x))
print is_atom(Not(x > 0))
print is_atom(f(x))
print is_atom(x)
print is_term(f(x))
print is_term(g(x))
print is_term(x)
print is_term(Var(1, IntSort()))