检查公式是否是Z3Py中的术语

时间:2013-01-03 15:31:42

标签: python z3

在Z3Py中,我需要使用标准语法term := const | var | f(t1,...,tn)来检查某个词是否是一个术语。我已经编写了以下函数来确定但是我的方法来检查n-ary函数是否看起来不是最优的。

有没有更好的方法呢?这些实用程序函数is_termis_atomis_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

2 个答案:

答案 0 :(得分:1)

功能合理,有几条评论:

  1. 这取决于您的规范中“var”的含义。 Z3的变量为de-Brujin指数。在z3py“is_var(a)”中有一个函数来检查“a”是否是变量索引。

  2. 还有另一个布尔连接词Z3_OP_XOR。

  3. 还有其他关系操作,例如比较位向量的操作。 这取决于你的意图和代码的用法,但你可以检查是否 表达式的排序是布尔值,如果确保头函数符号是 未解释的。

  4. is_const(a)定义为return is_app(a)和a.num_args()== 0.所以is_const实际上是由默认情况处理的。

  5. Z3因简化,解析或其他转换而创建的表达式可能包含许多共享子表达式。因此,直接递归下降可以在表达式的DAG大小中采用指数时间。您可以通过维护受访节点的哈希表来处理此问题。从Python中,您可以使用Z3_get_ast_id来检索表达式的唯一编号,并将其保存在集合中。只要术语不是垃圾收集,标识符就是唯一的 你应该将这样的一组保存为局部变量。

  6. 所以,有些东西:

     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)) > 0f(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)

在其他情况下,我们希望以特殊方式处理布尔连接词(AndOr,...)。例如,我们正在定义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()))