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

Python 检查公式是否为Z3Py中的术语,python,z3,Python,Z3,在Z3Py中,我需要使用标准语法术语:=const | var | f(t1,…,tn))检查某个词是否是术语。我编写了下面的函数来确定这一点,但是我检查n元函数的方法似乎不是很理想 有没有更好的办法?这些实用程序函数是术语,是原子,是文字,等等都有助于包含在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_

在Z3Py中,我需要使用标准语法
术语:=const | var | f(t1,…,tn)
)检查某个词是否是术语。我编写了下面的函数来确定这一点,但是我检查n元函数的方法似乎不是很理想

有没有更好的办法?这些实用程序函数
是术语
是原子
是文字
,等等都有助于包含在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

功能合理,有几点意见:

  • 这取决于规范中“var”的含义。Z3具有德布鲁金指数等变量。z3py“is_var(a)”中有一个函数,用于检查“a”是否为变量索引

  • 还有另一个布尔连接词Z3_OP_XOR

  • 还有其他关系操作,例如比较位向量的操作。 这取决于您的意图和代码的使用,但是您也可以检查 表达式的排序是布尔型的,如果是,请确保head函数符号是 毫无疑问

  • is_const(a)定义为返回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, {})
    
    一阶逻辑中使用的术语、原子和文字的“教科书”定义不能直接应用于Z3表达式。在Z3中,我们允许表达式如
    f(和(a,b))>0
    f(ForAll([x],g(x)==0))
    ,其中
    f
    是从布尔值到整数的函数。这种扩展不会增加表达能力,但在编写问题时非常方便。SMT 2.0标准还允许“术语”
    if-then-else
    表达式。这是另一个允许我们在“术语”中嵌套“公式”的特性。示例:
    g(如果(和(a,b),1,0))

    在实现操作Z3表达式的过程时,我们有时需要区分布尔表达式和非布尔表达式。在本例中,“术语”只是一个没有布尔排序的表达式

    def is_term(a):
       return not is_bool(a)
    
    在其他情况下,我们希望以特殊方式处理布尔连接词(
    ,…)。例如,我们正在定义一个CNF转换器。在本例中,我们将“原子”定义为任何不是量词、是(自由)变量或不是布尔连接词之一的应用程序的布尔表达式

    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)))
    
    以下是演示这些功能的示例(也可在线访问):

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