Substituting function symbols in z3 formulas

后端 未结 1 1398
眼角桃花
眼角桃花 2020-12-19 14:48

What is the best way to substitute a function symbol (with another function) in a formula? Z3py\'s substitute seems to only work with expressions, and what I do

相关标签:
1条回答
  • 2020-12-19 15:09

    We can implement a simple bottom-up rewriter that given a term s, a function f and term t will replace every f-application f(r_1, ..., r_n) in s with t[r_1, ..., r_n]. I'm using the notation t[r_1, ..., r_n] to denote the term obtained by replacing the free-variables in t with the terms r_1, ..., r_n.

    The rewriter can be implemented the Z3 API. I use an AstMap to cache results, and a todo list to store expressions that still have to be processed.

    Here is a simple example that replaces f-applications of the form f(t) with g(t+1) in s.

    x = Var(0, IntSort())
    print rewrite(s, f, g(x + 1))
    

    Here is the code and more examples. Beware, I only tested the code in a small set of examples.

    from z3 import *
    
    def update_term(t, args):
        # Update the children of term t with args. 
        # len(args) must be equal to the number of children in t.
        # If t is an application, then len(args) == t.num_args()
        # If t is a quantifier, then len(args) == 1
        n = len(args)
        _args = (Ast * n)()
        for i in range(n):
            _args[i] = args[i].as_ast()
        return z3._to_expr_ref(Z3_update_term(t.ctx_ref(), t.as_ast(), n, _args), t.ctx)
    
    def rewrite(s, f, t):
        """
        Replace f-applications f(r_1, ..., r_n) with t[r_1, ..., r_n] in s.
        """
        todo = [] # to do list
        todo.append(s)
        cache = AstMap(ctx=s.ctx)
        while todo:
            n = todo[len(todo) - 1]
            if is_var(n):
                todo.pop()
                cache[n] = n
            elif is_app(n):
                visited  = True
                new_args = []
                for i in range(n.num_args()):
                    arg = n.arg(i)
                    if not arg in cache:
                        todo.append(arg)
                        visited = False
                    else:
                        new_args.append(cache[arg])
                if visited:
                    todo.pop()
                    g = n.decl()
                    if eq(g, f):
                        new_n = substitute_vars(t, *new_args)
                    else:
                        new_n = update_term(n, new_args)
                    cache[n] = new_n
            else:
                assert(is_quantifier(n))
                b = n.body()
                if b in cache:
                    todo.pop()
                    new_n = update_term(n, [ cache[b] ])
                    cache[n] = new_n
                else:
                    todo.append(b)
        return cache[s]
    
    f = Function('f', IntSort(), IntSort())
    a, b = Ints('a b')
    s = Or(f(a) == 0, f(a) == 1, f(a+a) == 2)
    # Example 1: replace all f-applications with b
    print rewrite(s, f, b)
    
    # Example 2: replace all f-applications f(t) with g(t+1)
    g = Function('g', IntSort(), IntSort())
    x = Var(0, IntSort())
    print rewrite(s, f, g(x + 1))
    
    # Now, f and g are binary functions.
    f = Function('f', IntSort(), IntSort(), IntSort())
    g = Function('g', IntSort(), IntSort(), IntSort())
    
    # Example 3: replace all f-applications f(t1, t2) with g(t2, t1)
    s = Or(f(a, f(a, b)) == 0, f(b, a) == 1, f(f(1,0), 0) == 2)
    # The first argument is variable 0, and the second is variable 1.
    y = Var(1, IntSort())
    print rewrite(s, f, g(y, x))
    
    # Example 4: quantifiers
    s = ForAll([a], f(a, b) >= 0)
    print rewrite(s, f, g(y, x + 1))
    
    0 讨论(0)
提交回复
热议问题