mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	integrate lambda expressions
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									bf4edef761
								
							
						
					
					
						commit
						520ce9a5ee
					
				
					 139 changed files with 2243 additions and 1506 deletions
				
			
		| 
						 | 
				
			
			@ -27,6 +27,7 @@ Version 4.8.0
 | 
			
		|||
     Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged
 | 
			
		||||
     as lemmas (redundant) and are garbage collected if their glue level is high.
 | 
			
		||||
   - Substantial overhaul of the spacer horn clause engine.
 | 
			
		||||
   - Added basic features to support Lambda expressions.
 | 
			
		||||
 | 
			
		||||
- Removed features:
 | 
			
		||||
  - interpolation API
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ extern "C" {
 | 
			
		|||
        Z3_CATCH_RETURN(nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_mk_select(c, a, i);
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +100,7 @@ extern "C" {
 | 
			
		|||
        Z3_CATCH_RETURN(nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_mk_store(c, a, i, v);
 | 
			
		||||
| 
						 | 
				
			
			@ -155,6 +157,7 @@ extern "C" {
 | 
			
		|||
        Z3_CATCH_RETURN(nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_mk_map(c, f, n, args);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -808,8 +808,7 @@ extern "C" {
 | 
			
		|||
        expr * a = to_expr(_a);
 | 
			
		||||
        expr * const * to   = to_exprs(_to);
 | 
			
		||||
        var_subst subst(m, false);
 | 
			
		||||
        expr_ref new_a(m);
 | 
			
		||||
        subst(a, num_exprs, to, new_a);
 | 
			
		||||
        expr_ref new_a = subst(a, num_exprs, to);
 | 
			
		||||
        mk_c(c)->save_ast_trail(new_a);
 | 
			
		||||
        RETURN_Z3(of_expr(new_a.get()));
 | 
			
		||||
        Z3_CATCH_RETURN(nullptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -910,6 +909,7 @@ extern "C" {
 | 
			
		|||
            case PR_TRANSITIVITY_STAR: return Z3_OP_PR_TRANSITIVITY_STAR;
 | 
			
		||||
            case PR_MONOTONICITY: return Z3_OP_PR_MONOTONICITY;
 | 
			
		||||
            case PR_QUANT_INTRO: return Z3_OP_PR_QUANT_INTRO;
 | 
			
		||||
            case PR_BIND: return Z3_OP_PR_BIND;
 | 
			
		||||
            case PR_DISTRIBUTIVITY: return Z3_OP_PR_DISTRIBUTIVITY;
 | 
			
		||||
            case PR_AND_ELIM: return Z3_OP_PR_AND_ELIM;
 | 
			
		||||
            case PR_NOT_OR_ELIM: return Z3_OP_PR_NOT_OR_ELIM;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -173,6 +173,7 @@ extern "C" {
 | 
			
		|||
        to_optimize_ptr(o)->get_model(_m);
 | 
			
		||||
        Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); 
 | 
			
		||||
        if (_m) {
 | 
			
		||||
            if (mk_c(c)->params().m_model_compress) _m->compress();
 | 
			
		||||
            m_ref->m_model = _m;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ extern "C" {
 | 
			
		|||
        expr_ref result(mk_c(c)->m());
 | 
			
		||||
        if (num_decls > 0) {
 | 
			
		||||
            result = mk_c(c)->m().mk_quantifier(
 | 
			
		||||
                (0 != is_forall),
 | 
			
		||||
                is_forall ? forall_k : exists_k,
 | 
			
		||||
                names.size(), ts, names.c_ptr(), to_expr(body),
 | 
			
		||||
                weight,
 | 
			
		||||
                qid,
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +144,61 @@ extern "C" {
 | 
			
		|||
        return Z3_mk_quantifier(c, 0, weight, num_patterns, patterns, num_decls, types, decl_names, body);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_lambda(Z3_context c,
 | 
			
		||||
                               unsigned num_decls, Z3_sort const types[],
 | 
			
		||||
                               Z3_symbol const decl_names[],
 | 
			
		||||
                               Z3_ast body) {
 | 
			
		||||
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_mk_lambda(c, num_decls, types, decl_names, body);
 | 
			
		||||
        RESET_ERROR_CODE();
 | 
			
		||||
        expr_ref result(mk_c(c)->m());
 | 
			
		||||
        if (num_decls == 0) {
 | 
			
		||||
            SET_ERROR_CODE(Z3_INVALID_USAGE);
 | 
			
		||||
            RETURN_Z3(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sort* const* ts = reinterpret_cast<sort * const*>(types);
 | 
			
		||||
        svector<symbol> names;
 | 
			
		||||
        for (unsigned i = 0; i < num_decls; ++i) {
 | 
			
		||||
            names.push_back(to_symbol(decl_names[i]));
 | 
			
		||||
        }
 | 
			
		||||
        result = mk_c(c)->m().mk_lambda(names.size(), ts, names.c_ptr(), to_expr(body));
 | 
			
		||||
        mk_c(c)->save_ast_trail(result.get());
 | 
			
		||||
        return of_ast(result.get());
 | 
			
		||||
        Z3_CATCH_RETURN(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_lambda_const(Z3_context c, 
 | 
			
		||||
                                     unsigned num_decls, Z3_app const vars[],
 | 
			
		||||
                                     Z3_ast body) {
 | 
			
		||||
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_mk_lambda_const(c, num_decls, vars, body);
 | 
			
		||||
        RESET_ERROR_CODE();
 | 
			
		||||
        if (num_decls == 0) {
 | 
			
		||||
            SET_ERROR_CODE(Z3_INVALID_USAGE);
 | 
			
		||||
            RETURN_Z3(0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        svector<symbol>  _names;
 | 
			
		||||
        ptr_vector<sort> _vars;
 | 
			
		||||
        ptr_vector<expr> _args;
 | 
			
		||||
        for (unsigned i = 0; i < num_decls; ++i) {
 | 
			
		||||
            app* a = to_app(vars[i]);
 | 
			
		||||
            _names.push_back(to_app(a)->get_decl()->get_name());
 | 
			
		||||
            _args.push_back(a);
 | 
			
		||||
            _vars.push_back(mk_c(c)->m().get_sort(a));
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref result(mk_c(c)->m());        
 | 
			
		||||
        expr_abstract(mk_c(c)->m(), 0, num_decls, _args.c_ptr(), to_expr(body), result);
 | 
			
		||||
        
 | 
			
		||||
        result = mk_c(c)->m().mk_lambda(_vars.size(), _vars.c_ptr(), _names.c_ptr(), result);
 | 
			
		||||
        mk_c(c)->save_ast_trail(result.get());
 | 
			
		||||
        return of_ast(result.get());
 | 
			
		||||
        Z3_CATCH_RETURN(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_quantifier_const_ex(Z3_context c,
 | 
			
		||||
                                            Z3_bool is_forall,
 | 
			
		||||
| 
						 | 
				
			
			@ -292,17 +347,27 @@ extern "C" {
 | 
			
		|||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_is_quantifier_forall(c, a);
 | 
			
		||||
        RESET_ERROR_CODE();
 | 
			
		||||
        ast * _a = to_ast(a);
 | 
			
		||||
        if (_a->get_kind() == AST_QUANTIFIER) {
 | 
			
		||||
            return to_quantifier(_a)->is_forall();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            SET_ERROR_CODE(Z3_SORT_ERROR);
 | 
			
		||||
            return Z3_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
        return ::is_forall(to_ast(a)) ? Z3_TRUE : Z3_FALSE;
 | 
			
		||||
        Z3_CATCH_RETURN(Z3_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_is_quantifier_exists(c, a);
 | 
			
		||||
        RESET_ERROR_CODE();
 | 
			
		||||
        return ::is_exists(to_ast(a))  ? Z3_TRUE : Z3_FALSE;
 | 
			
		||||
        Z3_CATCH_RETURN(Z3_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_is_lambda(c, a);
 | 
			
		||||
        RESET_ERROR_CODE();
 | 
			
		||||
        return ::is_lambda(to_ast(a))  ? Z3_TRUE : Z3_FALSE;
 | 
			
		||||
        Z3_CATCH_RETURN(Z3_FALSE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    unsigned Z3_API Z3_get_quantifier_weight(Z3_context c, Z3_ast a) {
 | 
			
		||||
        Z3_TRY;
 | 
			
		||||
        LOG_Z3_get_quantifier_weight(c, a);
 | 
			
		||||
| 
						 | 
				
			
			@ -485,3 +550,4 @@ extern "C" {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -433,6 +433,9 @@ extern "C" {
 | 
			
		|||
            SET_ERROR_CODE(Z3_INVALID_USAGE);
 | 
			
		||||
            RETURN_Z3(nullptr);
 | 
			
		||||
        }
 | 
			
		||||
        if (_m) {
 | 
			
		||||
            if (mk_c(c)->params().m_model_compress) _m->compress();
 | 
			
		||||
        }
 | 
			
		||||
        Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); 
 | 
			
		||||
        m_ref->m_model = _m;
 | 
			
		||||
        mk_c(c)->save_object(m_ref);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -252,7 +252,6 @@ namespace z3 {
 | 
			
		|||
        */
 | 
			
		||||
        sort array_sort(sort d, sort r);
 | 
			
		||||
        sort array_sort(sort_vector const& d, sort r);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
           \brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1].
 | 
			
		||||
           \c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements,
 | 
			
		||||
| 
						 | 
				
			
			@ -675,7 +674,21 @@ namespace z3 {
 | 
			
		|||
           \brief Return true if this expression is a quantifier.
 | 
			
		||||
        */
 | 
			
		||||
        bool is_quantifier() const { return kind() == Z3_QUANTIFIER_AST; }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
           \brief Return true if this expression is a universal quantifier.
 | 
			
		||||
        */
 | 
			
		||||
        bool is_forall() const { return 0 != Z3_is_quantifier_forall(ctx(), m_ast); }
 | 
			
		||||
        /**
 | 
			
		||||
           \brief Return true if this expression is an existential quantifier.
 | 
			
		||||
        */
 | 
			
		||||
        bool is_exists() const { return 0 != Z3_is_quantifier_exists(ctx(), m_ast); }
 | 
			
		||||
        /**
 | 
			
		||||
           \brief Return true if this expression is a lambda expression.
 | 
			
		||||
        */
 | 
			
		||||
        bool is_lambda() const { return 0 != Z3_is_lambda(ctx(), m_ast); }
 | 
			
		||||
        /**
 | 
			
		||||
 | 
			
		||||
           \brief Return true if this expression is a variable.
 | 
			
		||||
        */
 | 
			
		||||
        bool is_var() const { return kind() == Z3_VAR_AST; }
 | 
			
		||||
| 
						 | 
				
			
			@ -1638,6 +1651,31 @@ namespace z3 {
 | 
			
		|||
        array<Z3_app> vars(xs);
 | 
			
		||||
        Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr lambda(expr const & x, expr const & b) {
 | 
			
		||||
        check_context(x, b);
 | 
			
		||||
        Z3_app vars[] = {(Z3_app) x};
 | 
			
		||||
        Z3_ast r = Z3_mk_lambda_const(b.ctx(), 1, vars, b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr lambda(expr const & x1, expr const & x2, expr const & b) {
 | 
			
		||||
        check_context(x1, b); check_context(x2, b);
 | 
			
		||||
        Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
 | 
			
		||||
        Z3_ast r = Z3_mk_lambda_const(b.ctx(), 2, vars, b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr lambda(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
 | 
			
		||||
        check_context(x1, b); check_context(x2, b); check_context(x3, b);
 | 
			
		||||
        Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
 | 
			
		||||
        Z3_ast r = Z3_mk_lambda_const(b.ctx(), 3, vars, b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr lambda(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
 | 
			
		||||
        check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
 | 
			
		||||
        Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
 | 
			
		||||
        Z3_ast r = Z3_mk_lambda_const(b.ctx(), 4, vars, b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr lambda(expr_vector const & xs, expr const & b) {
 | 
			
		||||
        array<Z3_app> vars(xs);
 | 
			
		||||
        Z3_ast r = Z3_mk_lambda_const(b.ctx(), vars.size(), vars.ptr(), b); b.check_error(); return expr(b.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline expr pble(expr_vector const& es, int const* coeffs, int bound) {
 | 
			
		||||
        assert(es.size() > 0);
 | 
			
		||||
        context& ctx = es[0].ctx();
 | 
			
		||||
| 
						 | 
				
			
			@ -2521,7 +2559,6 @@ namespace z3 {
 | 
			
		|||
        array<Z3_sort> dom(d);
 | 
			
		||||
        Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), r); check_error(); return sort(*this, s); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) {
 | 
			
		||||
        array<Z3_symbol> _enum_names(n);
 | 
			
		||||
        for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); }
 | 
			
		||||
| 
						 | 
				
			
			@ -2785,12 +2822,8 @@ namespace z3 {
 | 
			
		|||
        a.check_error();
 | 
			
		||||
        return expr(a.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
    inline expr select(expr const & a, int i) { return select(a, a.ctx().num_val(i, a.get_sort().array_domain())); }
 | 
			
		||||
    inline expr store(expr const & a, expr const & i, expr const & v) {
 | 
			
		||||
        check_context(a, i); check_context(a, v);
 | 
			
		||||
        Z3_ast r = Z3_mk_store(a.ctx(), a, i, v);
 | 
			
		||||
        a.check_error();
 | 
			
		||||
        return expr(a.ctx(), r);
 | 
			
		||||
    inline expr select(expr const & a, int i) { 
 | 
			
		||||
        return select(a, a.ctx().num_val(i, a.get_sort().array_domain())); 
 | 
			
		||||
    }
 | 
			
		||||
    inline expr select(expr const & a, expr_vector const & i) {
 | 
			
		||||
        check_context(a, i);
 | 
			
		||||
| 
						 | 
				
			
			@ -2800,6 +2833,13 @@ namespace z3 {
 | 
			
		|||
        return expr(a.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline expr store(expr const & a, expr const & i, expr const & v) {
 | 
			
		||||
        check_context(a, i); check_context(a, v);
 | 
			
		||||
        Z3_ast r = Z3_mk_store(a.ctx(), a, i, v);
 | 
			
		||||
        a.check_error();
 | 
			
		||||
        return expr(a.ctx(), r);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); }
 | 
			
		||||
    inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); }
 | 
			
		||||
    inline expr store(expr const & a, int i, int v) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,6 +84,7 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE
 | 
			
		|||
    IntNum.cs
 | 
			
		||||
    IntSort.cs
 | 
			
		||||
    IntSymbol.cs
 | 
			
		||||
    Lambda.cs
 | 
			
		||||
    ListSort.cs
 | 
			
		||||
    Log.cs
 | 
			
		||||
    Model.cs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3292,6 +3292,53 @@ namespace Microsoft.Z3
 | 
			
		|||
                return MkExists(boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Create a lambda expression.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// Creates a lambda expression.
 | 
			
		||||
        /// <paramref name="sorts"/> is an array
 | 
			
		||||
        /// with the sorts of the bound variables, <paramref name="names"/> is an array with the
 | 
			
		||||
        /// 'names' of the bound variables, and <paramref name="body"/> is the body of the
 | 
			
		||||
        /// lambda. 
 | 
			
		||||
        /// Note that the bound variables are de-Bruijn indices created using <see cref="MkBound"/>.
 | 
			
		||||
        /// Z3 applies the convention that the last element in <paramref name="names"/> and
 | 
			
		||||
        /// <paramref name="sorts"/> refers to the variable with index 0, the second to last element
 | 
			
		||||
        /// of <paramref name="names"/> and <paramref name="sorts"/> refers to the variable
 | 
			
		||||
        /// with index 1, etc.
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        /// <param name="sorts">the sorts of the bound variables.</param>
 | 
			
		||||
        /// <param name="names">names of the bound variables</param>
 | 
			
		||||
        /// <param name="body">the body of the quantifier.</param>
 | 
			
		||||
        public Lambda MkLambda(Sort[] sorts, Symbol[] names, Expr body)
 | 
			
		||||
        {
 | 
			
		||||
            Contract.Requires(sorts != null);
 | 
			
		||||
            Contract.Requires(names != null);
 | 
			
		||||
            Contract.Requires(body != null);
 | 
			
		||||
            Contract.Requires(sorts.Length == names.Length);
 | 
			
		||||
            Contract.Requires(Contract.ForAll(sorts, s => s != null));
 | 
			
		||||
            Contract.Requires(Contract.ForAll(names, n => n != null));
 | 
			
		||||
            Contract.Ensures(Contract.Result<Lambda>() != null);
 | 
			
		||||
            return new Lambda(this, sorts, names, body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Create a lambda expression.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        /// <remarks>
 | 
			
		||||
        /// Creates a lambda expression using a list of constants that will
 | 
			
		||||
        /// form the set of bound variables.
 | 
			
		||||
        /// <seealso cref="MkLambda(Sort[], Symbol[], Expr)"/>
 | 
			
		||||
        /// </remarks>
 | 
			
		||||
        public Lambda MkLambda(Expr[] boundConstants, Expr body)
 | 
			
		||||
        {
 | 
			
		||||
            Contract.Requires(body != null);
 | 
			
		||||
            Contract.Requires(boundConstants != null && Contract.ForAll(boundConstants, b => b != null));
 | 
			
		||||
            Contract.Ensures(Contract.Result<Lambda>() != null);
 | 
			
		||||
            return new Lambda(this, boundConstants, body);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        #endregion // Expr
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ namespace Microsoft.Z3
 | 
			
		|||
        /// </summary>
 | 
			
		||||
        public bool IsExistential
 | 
			
		||||
        {
 | 
			
		||||
            get { return !IsUniversal; }
 | 
			
		||||
            get { return Native.Z3_is_quantifier_exists(Context.nCtx, NativeObject) != 0; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,6 +141,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES
 | 
			
		|||
  IntNum.java
 | 
			
		||||
  IntSort.java
 | 
			
		||||
  IntSymbol.java
 | 
			
		||||
  Lambda.java
 | 
			
		||||
  ListSort.java
 | 
			
		||||
  Log.java
 | 
			
		||||
  ModelDecRefQueue.java
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -518,7 +518,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a fresh constant function declaration with a name prefixed with
 | 
			
		||||
     * {@code prefix"}. 
 | 
			
		||||
     * {@code prefix}. 
 | 
			
		||||
     * @see #mkFuncDecl(String,Sort,Sort)
 | 
			
		||||
     * @see #mkFuncDecl(String,Sort[],Sort)
 | 
			
		||||
     **/
 | 
			
		||||
| 
						 | 
				
			
			@ -696,7 +696,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the equality {@code x"/> = <paramref name="y}.
 | 
			
		||||
     * Creates the equality {@code x = y}
 | 
			
		||||
     **/
 | 
			
		||||
    public BoolExpr mkEq(Expr x, Expr y)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2498,6 +2498,40 @@ public class Context implements AutoCloseable {
 | 
			
		|||
                    quantifierID, skolemID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a lambda expression.
 | 
			
		||||
     * 
 | 
			
		||||
     * {@code sorts} is an array
 | 
			
		||||
     * with the sorts of the bound variables, {@code names} is an array with the
 | 
			
		||||
     * 'names' of the bound variables, and {@code body} is the body of the
 | 
			
		||||
     * lambda. 
 | 
			
		||||
     * Note that the bound variables are de-Bruijn indices created using {@see #MkBound}
 | 
			
		||||
     * Z3 applies the convention that the last element in {@code names} and
 | 
			
		||||
     * {@code sorts} refers to the variable with index 0, the second to last element
 | 
			
		||||
     * of {@code names} and {@code sorts} refers to the variable
 | 
			
		||||
     * with index 1, etc.
 | 
			
		||||
     *
 | 
			
		||||
     * @param sorts the sorts of the bound variables.
 | 
			
		||||
     * @param names names of the bound variables.
 | 
			
		||||
     * @param body the body of the quantifier.
 | 
			
		||||
     **/
 | 
			
		||||
     public Lambda mkLambda(Sort[] sorts, Symbol[] names, Expr body)
 | 
			
		||||
     {
 | 
			
		||||
         return Lambda.of(this, sorts, names, body);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a lambda expression.
 | 
			
		||||
     * 
 | 
			
		||||
     * Creates a lambda expression using a list of constants that will
 | 
			
		||||
     * form the set of bound variables.
 | 
			
		||||
     **/
 | 
			
		||||
     public Lambda mkLambda(Expr[] boundConstants, Expr body)
 | 
			
		||||
     {
 | 
			
		||||
         return Lambda.of(this, boundConstants, body);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Selects the format used for pretty-printing expressions.
 | 
			
		||||
     * Remarks:  The
 | 
			
		||||
| 
						 | 
				
			
			@ -2653,7 +2687,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a tactic that applies {@code t1} to a Goal and then
 | 
			
		||||
     * {@code t2"/> to every subgoal produced by <paramref name="t1}.
 | 
			
		||||
     * {@code t2} to every subgoal produced by {@code t1}
 | 
			
		||||
     **/
 | 
			
		||||
    public Tactic andThen(Tactic t1, Tactic t2, Tactic... ts)
 | 
			
		||||
           
 | 
			
		||||
| 
						 | 
				
			
			@ -2734,7 +2768,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a tactic that applies {@code t1} to a given goal if the
 | 
			
		||||
     * probe {@code p"/> evaluates to true and <paramref name="t2}
 | 
			
		||||
     * probe {@code p} evaluates to true and {@code t2}
 | 
			
		||||
     * otherwise.
 | 
			
		||||
     **/
 | 
			
		||||
    public Tactic cond(Probe p, Tactic t1, Tactic t2)
 | 
			
		||||
| 
						 | 
				
			
			@ -2895,7 +2929,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value returned by
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value returned by
 | 
			
		||||
     * {@code p1} is less than the value returned by {@code p2}
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe lt(Probe p1, Probe p2)
 | 
			
		||||
| 
						 | 
				
			
			@ -2907,7 +2941,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value returned by
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value returned by
 | 
			
		||||
     * {@code p1} is greater than the value returned by {@code p2}
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe gt(Probe p1, Probe p2)
 | 
			
		||||
| 
						 | 
				
			
			@ -2919,7 +2953,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value returned by
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value returned by
 | 
			
		||||
     * {@code p1} is less than or equal the value returned by
 | 
			
		||||
     * {@code p2}
 | 
			
		||||
     **/
 | 
			
		||||
| 
						 | 
				
			
			@ -2932,7 +2966,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value returned by
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value returned by
 | 
			
		||||
     * {@code p1} is greater than or equal the value returned by
 | 
			
		||||
     * {@code p2}
 | 
			
		||||
     **/
 | 
			
		||||
| 
						 | 
				
			
			@ -2945,7 +2979,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value returned by
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value returned by
 | 
			
		||||
     * {@code p1} is equal to the value returned by {@code p2}
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe eq(Probe p1, Probe p2)
 | 
			
		||||
| 
						 | 
				
			
			@ -2957,7 +2991,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value {@code p1} and {@code p2} evaluate to "true".
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value {@code p1} and {@code p2} evaluate to {@code true}.
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe and(Probe p1, Probe p2)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2968,7 +3002,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value {@code p1} or {@code p2} evaluate to "true".
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value {@code p1} or {@code p2} evaluate to {@code true}.
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe or(Probe p1, Probe p2)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -2979,7 +3013,7 @@ public class Context implements AutoCloseable {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a probe that evaluates to "true" when the value {@code p} does not evaluate to "true".
 | 
			
		||||
     * Create a probe that evaluates to {@code true} when the value {@code p} does not evaluate to {@code true}.
 | 
			
		||||
     **/
 | 
			
		||||
    public Probe not(Probe p)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ public class Quantifier extends BoolExpr
 | 
			
		|||
     **/
 | 
			
		||||
    public boolean isExistential()
 | 
			
		||||
    {
 | 
			
		||||
        return !isUniversal();
 | 
			
		||||
        return Native.isQuantifierExists(getContext().nCtx(), getNativeObject());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1766,6 +1766,34 @@ class QuantifierRef(BoolRef):
 | 
			
		|||
        """
 | 
			
		||||
        return Z3_is_quantifier_forall(self.ctx_ref(), self.ast)
 | 
			
		||||
 | 
			
		||||
    def is_exists(self):
 | 
			
		||||
        """Return `True` if `self` is an existential quantifier.
 | 
			
		||||
 | 
			
		||||
        >>> f = Function('f', IntSort(), IntSort())
 | 
			
		||||
        >>> x = Int('x')
 | 
			
		||||
        >>> q = ForAll(x, f(x) == 0)
 | 
			
		||||
        >>> q.is_exists()
 | 
			
		||||
        False
 | 
			
		||||
        >>> q = Exists(x, f(x) != 0)
 | 
			
		||||
        >>> q.is_exists()
 | 
			
		||||
        True
 | 
			
		||||
        """
 | 
			
		||||
        return Z3_is_quantifier_exists(self.ctx_ref(), self.ast)
 | 
			
		||||
 | 
			
		||||
    def is_lambda(self):
 | 
			
		||||
        """Return `True` if `self` is a lambda expression.
 | 
			
		||||
 | 
			
		||||
        >>> f = Function('f', IntSort(), IntSort())
 | 
			
		||||
        >>> x = Int('x')
 | 
			
		||||
        >>> q = Lambda(x, f(x))
 | 
			
		||||
        >>> q.is_lambda()
 | 
			
		||||
        True
 | 
			
		||||
        >>> q = Exists(x, f(x) != 0)
 | 
			
		||||
        >>> q.is_lambda()
 | 
			
		||||
        False
 | 
			
		||||
        """
 | 
			
		||||
        return Z3_is_lambda(self.ctx_ref(), self.ast)
 | 
			
		||||
 | 
			
		||||
    def weight(self):
 | 
			
		||||
        """Return the weight annotation of `self`.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1973,6 +2001,26 @@ def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
 | 
			
		|||
    """
 | 
			
		||||
    return _mk_quantifier(False, vs, body, weight, qid, skid, patterns, no_patterns)
 | 
			
		||||
 | 
			
		||||
def Lambda(vs, body):
 | 
			
		||||
    """Create a Z3 lambda expression.
 | 
			
		||||
 | 
			
		||||
    >>> f = Function('f', IntSort(), IntSort(), IntSort())
 | 
			
		||||
    >>> mem0 = Array('mem0', IntSort(), IntSort())
 | 
			
		||||
    >>> lo, hi, e, i = Ints('lo hi e i')
 | 
			
		||||
    >>> mem1 = Lambda([i], If(And(lo <= i, i <= hi), e, mem0[i]))
 | 
			
		||||
    >>> mem1
 | 
			
		||||
    Lambda(i, If(And(lo <= i, i <= hi), e, mem0[i]))
 | 
			
		||||
    """
 | 
			
		||||
    ctx = body.ctx
 | 
			
		||||
    if is_app(vs):
 | 
			
		||||
        vs = [vs]
 | 
			
		||||
    num_vars = len(vs)
 | 
			
		||||
    _vs = (Ast * num_vars)()
 | 
			
		||||
    for i in range(num_vars):
 | 
			
		||||
        ## TODO: Check if is constant
 | 
			
		||||
        _vs[i] = vs[i].as_ast()
 | 
			
		||||
    return QuantifierRef(Z3_mk_lambda_const(ctx.ref(), num_vars, _vs, body.as_ast()), ctx)
 | 
			
		||||
 | 
			
		||||
#########################################
 | 
			
		||||
#
 | 
			
		||||
# Arithmetic
 | 
			
		||||
| 
						 | 
				
			
			@ -5582,7 +5630,7 @@ class FuncEntry:
 | 
			
		|||
        >>> m = s.model()
 | 
			
		||||
        >>> f_i = m[f]
 | 
			
		||||
        >>> f_i.num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        >>> e = f_i.entry(0)
 | 
			
		||||
        >>> e.num_args()
 | 
			
		||||
        2
 | 
			
		||||
| 
						 | 
				
			
			@ -5600,16 +5648,16 @@ class FuncEntry:
 | 
			
		|||
        >>> m = s.model()
 | 
			
		||||
        >>> f_i = m[f]
 | 
			
		||||
        >>> f_i.num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        >>> e = f_i.entry(0)
 | 
			
		||||
        >>> e
 | 
			
		||||
        [0, 1, 10]
 | 
			
		||||
        [1, 2, 20]
 | 
			
		||||
        >>> e.num_args()
 | 
			
		||||
        2
 | 
			
		||||
        >>> e.arg_value(0)
 | 
			
		||||
        0
 | 
			
		||||
        >>> e.arg_value(1)
 | 
			
		||||
        1
 | 
			
		||||
        >>> e.arg_value(1)
 | 
			
		||||
        2
 | 
			
		||||
        >>> try:
 | 
			
		||||
        ...   e.arg_value(2)
 | 
			
		||||
        ... except IndexError:
 | 
			
		||||
| 
						 | 
				
			
			@ -5631,14 +5679,14 @@ class FuncEntry:
 | 
			
		|||
        >>> m = s.model()
 | 
			
		||||
        >>> f_i = m[f]
 | 
			
		||||
        >>> f_i.num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        >>> e = f_i.entry(0)
 | 
			
		||||
        >>> e
 | 
			
		||||
        [0, 1, 10]
 | 
			
		||||
        [1, 2, 20]
 | 
			
		||||
        >>> e.num_args()
 | 
			
		||||
        2
 | 
			
		||||
        >>> e.value()
 | 
			
		||||
        10
 | 
			
		||||
        20
 | 
			
		||||
        """
 | 
			
		||||
        return _to_expr_ref(Z3_func_entry_get_value(self.ctx.ref(), self.entry), self.ctx)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5652,10 +5700,10 @@ class FuncEntry:
 | 
			
		|||
        >>> m = s.model()
 | 
			
		||||
        >>> f_i = m[f]
 | 
			
		||||
        >>> f_i.num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        >>> e = f_i.entry(0)
 | 
			
		||||
        >>> e.as_list()
 | 
			
		||||
        [0, 1, 10]
 | 
			
		||||
        [1, 2, 20]
 | 
			
		||||
        """
 | 
			
		||||
        args = [ self.arg_value(i) for i in range(self.num_args())]
 | 
			
		||||
        args.append(self.value())
 | 
			
		||||
| 
						 | 
				
			
			@ -5693,7 +5741,7 @@ class FuncInterp(Z3PPObject):
 | 
			
		|||
        sat
 | 
			
		||||
        >>> m = s.model()
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
 | 
			
		||||
        [2 -> 0, else -> 1]
 | 
			
		||||
        >>> m[f].else_value()
 | 
			
		||||
        1
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -5713,9 +5761,9 @@ class FuncInterp(Z3PPObject):
 | 
			
		|||
        sat
 | 
			
		||||
        >>> m = s.model()
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
 | 
			
		||||
        [2 -> 0, else -> 1]
 | 
			
		||||
        >>> m[f].num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        """
 | 
			
		||||
        return int(Z3_func_interp_get_num_entries(self.ctx.ref(), self.f))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5743,14 +5791,10 @@ class FuncInterp(Z3PPObject):
 | 
			
		|||
        sat
 | 
			
		||||
        >>> m = s.model()
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
 | 
			
		||||
        [2 -> 0, else -> 1]
 | 
			
		||||
        >>> m[f].num_entries()
 | 
			
		||||
        3
 | 
			
		||||
        1
 | 
			
		||||
        >>> m[f].entry(0)
 | 
			
		||||
        [0, 1]
 | 
			
		||||
        >>> m[f].entry(1)
 | 
			
		||||
        [1, 1]
 | 
			
		||||
        >>> m[f].entry(2)
 | 
			
		||||
        [2, 0]
 | 
			
		||||
        """
 | 
			
		||||
        if idx >= self.num_entries():
 | 
			
		||||
| 
						 | 
				
			
			@ -5777,9 +5821,9 @@ class FuncInterp(Z3PPObject):
 | 
			
		|||
        sat
 | 
			
		||||
        >>> m = s.model()
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [0 -> 1, 1 -> 1, 2 -> 0, else -> 1]
 | 
			
		||||
        [2 -> 0, else -> 1]
 | 
			
		||||
        >>> m[f].as_list()
 | 
			
		||||
        [[0, 1], [1, 1], [2, 0], 1]
 | 
			
		||||
        [[2, 0], 1]
 | 
			
		||||
        """
 | 
			
		||||
        r = [ self.entry(i).as_list() for i in range(self.num_entries())]
 | 
			
		||||
        r.append(self.else_value())
 | 
			
		||||
| 
						 | 
				
			
			@ -5891,7 +5935,7 @@ class ModelRef(Z3PPObject):
 | 
			
		|||
        >>> m[x]
 | 
			
		||||
        1
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [1 -> 0, else -> 0]
 | 
			
		||||
        [else -> 0]
 | 
			
		||||
        """
 | 
			
		||||
        if __debug__:
 | 
			
		||||
            _z3_assert(isinstance(decl, FuncDeclRef) or is_const(decl), "Z3 declaration expected")
 | 
			
		||||
| 
						 | 
				
			
			@ -6008,10 +6052,10 @@ class ModelRef(Z3PPObject):
 | 
			
		|||
        >>> m[x]
 | 
			
		||||
        1
 | 
			
		||||
        >>> m[f]
 | 
			
		||||
        [1 -> 0, else -> 0]
 | 
			
		||||
        [else -> 0]
 | 
			
		||||
        >>> for d in m: print("%s -> %s" % (d, m[d]))
 | 
			
		||||
        x -> 1
 | 
			
		||||
        f -> [1 -> 0, else -> 0]
 | 
			
		||||
        f -> [else -> 0]
 | 
			
		||||
        """
 | 
			
		||||
        if _is_int(idx):
 | 
			
		||||
            if idx >= len(self):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -959,8 +959,10 @@ class Formatter:
 | 
			
		|||
            ys_pp   = seq3(ys, '[', ']')
 | 
			
		||||
        if a.is_forall():
 | 
			
		||||
            header = 'ForAll'
 | 
			
		||||
        else:
 | 
			
		||||
        elif a.is_exists():
 | 
			
		||||
            header = 'Exists'
 | 
			
		||||
        else:
 | 
			
		||||
            header = 'Lambda'
 | 
			
		||||
        return seq1(header, (ys_pp, body_pp))
 | 
			
		||||
 | 
			
		||||
    def pp_expr(self, a, d, xs):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -482,6 +482,10 @@ typedef enum
 | 
			
		|||
       T1: (~ p q)
 | 
			
		||||
       [quant-intro T1]: (~ (forall (x) p) (forall (x) q))
 | 
			
		||||
 | 
			
		||||
   - Z3_OP_PR_BIND: Given a proof p, produces a proof of lambda x . p, where x are free variables in p.
 | 
			
		||||
       T1: f
 | 
			
		||||
       [proof-bind T1] forall (x) f
 | 
			
		||||
 | 
			
		||||
   - Z3_OP_PR_DISTRIBUTIVITY: Distributivity proof object.
 | 
			
		||||
          Given that f (= or) distributes over g (= and), produces a proof for
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1109,6 +1113,7 @@ typedef enum {
 | 
			
		|||
    Z3_OP_PR_TRANSITIVITY_STAR,
 | 
			
		||||
    Z3_OP_PR_MONOTONICITY,
 | 
			
		||||
    Z3_OP_PR_QUANT_INTRO,
 | 
			
		||||
    Z3_OP_PR_BIND,
 | 
			
		||||
    Z3_OP_PR_DISTRIBUTIVITY,
 | 
			
		||||
    Z3_OP_PR_AND_ELIM,
 | 
			
		||||
    Z3_OP_PR_NOT_OR_ELIM,
 | 
			
		||||
| 
						 | 
				
			
			@ -1857,7 +1862,6 @@ extern "C" {
 | 
			
		|||
    */
 | 
			
		||||
    Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const * domain, Z3_sort range);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Create a tuple type.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2946,6 +2950,8 @@ extern "C" {
 | 
			
		|||
    */
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief n-ary Array read.
 | 
			
		||||
       The argument \c a is the array and \c idxs are the indices of the array that gets read.
 | 
			
		||||
| 
						 | 
				
			
			@ -2955,6 +2961,7 @@ extern "C" {
 | 
			
		|||
    */
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Array update.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2973,6 +2980,7 @@ extern "C" {
 | 
			
		|||
    */
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief n-ary Array update.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3763,6 +3771,54 @@ extern "C" {
 | 
			
		|||
        Z3_ast body
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Create a lambda expression. It taks an expression \c body that contains bound variables 
 | 
			
		||||
       of the same sorts as the sorts listed in the array \c sorts. The bound variables are de-Bruijn indices created
 | 
			
		||||
       using #Z3_mk_bound. The array \c decl_names contains the names that the quantified formula uses for the
 | 
			
		||||
       bound variables. Z3 applies the convention that the last element in the \c decl_names and \c sorts array
 | 
			
		||||
       refers to the variable with index 0, the second to last element of \c decl_names and \c sorts refers
 | 
			
		||||
       to the variable with index 1, etc.
 | 
			
		||||
       The sort of the resulting expression is \c (Array sorts range) where \c range is the sort of \c body.
 | 
			
		||||
       For example, if the lambda binds two variables of sort \c Int and \c Bool, and the \c body has sort \c Real, 
 | 
			
		||||
       the sort of the expression is \c (Array Int Bool Real).
 | 
			
		||||
 | 
			
		||||
       \param c logical context
 | 
			
		||||
       \param num_decls number of variables to be bound.
 | 
			
		||||
       \param sorts the sorts of the bound variables.
 | 
			
		||||
       \param decl_names names of the bound variables
 | 
			
		||||
       \param body the body of the lambda expression.       
 | 
			
		||||
 | 
			
		||||
       \sa Z3_mk_bound
 | 
			
		||||
       \sa Z3_mk_forall
 | 
			
		||||
       \sa Z3_mk_lambda_const
 | 
			
		||||
 | 
			
		||||
       def_API('Z3_mk_lambda', AST, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in_array(1, SYMBOL), _in(AST)))
 | 
			
		||||
    */
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_lambda(Z3_context c, 
 | 
			
		||||
                               unsigned num_decls, Z3_sort const sorts[],
 | 
			
		||||
                               Z3_symbol const decl_names[],
 | 
			
		||||
                               Z3_ast body);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Create a lambda expression using a list of constants that form the set
 | 
			
		||||
       of bound variables
 | 
			
		||||
 | 
			
		||||
       \param c logical context.
 | 
			
		||||
       \param num_bound number of constants to be abstracted into bound variables.
 | 
			
		||||
       \param bound array of constants to be abstracted into bound variables.
 | 
			
		||||
       \param body the body of the lambda expression.
 | 
			
		||||
 | 
			
		||||
       \sa Z3_mk_bound
 | 
			
		||||
       \sa Z3_mk_forall
 | 
			
		||||
       \sa Z3_mk_lambda
 | 
			
		||||
 | 
			
		||||
       def_API('Z3_mk_lambda_const', AST, (_in(CONTEXT), _in(UINT), _in_array(1, APP), _in(AST)))
 | 
			
		||||
    */
 | 
			
		||||
    Z3_ast Z3_API Z3_mk_lambda_const(Z3_context c, 
 | 
			
		||||
                                     unsigned num_bound, Z3_app const bound[],
 | 
			
		||||
                                     Z3_ast body);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /*@}*/
 | 
			
		||||
 | 
			
		||||
    /** @name Accessors */
 | 
			
		||||
| 
						 | 
				
			
			@ -4529,14 +4585,29 @@ extern "C" {
 | 
			
		|||
    unsigned Z3_API Z3_get_index_value(Z3_context c, Z3_ast a);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Determine if quantifier is universal.
 | 
			
		||||
 | 
			
		||||
       \pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
 | 
			
		||||
       \brief Determine if an ast is a universal quantifier.
 | 
			
		||||
 | 
			
		||||
       def_API('Z3_is_quantifier_forall', BOOL, (_in(CONTEXT), _in(AST)))
 | 
			
		||||
    */
 | 
			
		||||
    Z3_bool Z3_API Z3_is_quantifier_forall(Z3_context c, Z3_ast a);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Determine if ast is an existential quantifier.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
       def_API('Z3_is_quantifier_exists', BOOL, (_in(CONTEXT), _in(AST)))
 | 
			
		||||
    */
 | 
			
		||||
    Z3_bool Z3_API Z3_is_quantifier_exists(Z3_context c, Z3_ast a);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Determine if ast is a lambda expresion.
 | 
			
		||||
 | 
			
		||||
       \pre Z3_get_ast_kind(a) == Z3_QUANTIFIER_AST
 | 
			
		||||
 | 
			
		||||
       def_API('Z3_is_lambda', BOOL, (_in(CONTEXT), _in(AST)))
 | 
			
		||||
    */
 | 
			
		||||
    Z3_bool Z3_API Z3_is_lambda(Z3_context c, Z3_ast a);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Obtain weight of quantifier.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										142
									
								
								src/ast/ast.cpp
									
										
									
									
									
								
							
							
						
						
									
										142
									
								
								src/ast/ast.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -26,6 +26,9 @@ Revision History:
 | 
			
		|||
#include "util/string_buffer.h"
 | 
			
		||||
#include "ast/ast_util.h"
 | 
			
		||||
#include "ast/ast_smt2_pp.h"
 | 
			
		||||
#include "ast/array_decl_plugin.h"
 | 
			
		||||
#include "ast/ast_translation.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -360,13 +363,14 @@ app::app(func_decl * decl, unsigned num_args, expr * const * args):
 | 
			
		|||
//
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
 | 
			
		||||
quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
 | 
			
		||||
quantifier::quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
 | 
			
		||||
                       int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
 | 
			
		||||
                       unsigned num_no_patterns, expr * const * no_patterns):
 | 
			
		||||
    expr(AST_QUANTIFIER),
 | 
			
		||||
    m_forall(forall),
 | 
			
		||||
    m_kind(k),
 | 
			
		||||
    m_num_decls(num_decls),
 | 
			
		||||
    m_expr(body),
 | 
			
		||||
    m_sort(s),
 | 
			
		||||
    m_depth(::get_depth(body) + 1),
 | 
			
		||||
    m_weight(weight),
 | 
			
		||||
    m_has_unused_vars(true),
 | 
			
		||||
| 
						 | 
				
			
			@ -385,6 +389,25 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
 | 
			
		|||
        memcpy(const_cast<expr **>(get_no_patterns()), no_patterns, sizeof(expr *) * num_no_patterns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quantifier::quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s):
 | 
			
		||||
    expr(AST_QUANTIFIER),
 | 
			
		||||
    m_kind(lambda_k),
 | 
			
		||||
    m_num_decls(num_decls),
 | 
			
		||||
    m_expr(body),
 | 
			
		||||
    m_sort(s),
 | 
			
		||||
    m_depth(::get_depth(body) + 1),
 | 
			
		||||
    m_weight(0),
 | 
			
		||||
    m_has_unused_vars(true),
 | 
			
		||||
    m_has_labels(::has_labels(body)),
 | 
			
		||||
    m_qid(symbol()),
 | 
			
		||||
    m_skid(symbol()),
 | 
			
		||||
    m_num_patterns(0),
 | 
			
		||||
    m_num_no_patterns(0) {
 | 
			
		||||
    memcpy(const_cast<sort **>(get_decl_sorts()), decl_sorts, sizeof(sort *) * num_decls);
 | 
			
		||||
    memcpy(const_cast<symbol*>(get_decl_names()), decl_names, sizeof(symbol) * num_decls);   
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
//
 | 
			
		||||
// Auxiliary functions
 | 
			
		||||
| 
						 | 
				
			
			@ -392,21 +415,16 @@ quantifier::quantifier(bool forall, unsigned num_decls, sort * const * decl_sort
 | 
			
		|||
// -----------------------------------
 | 
			
		||||
 | 
			
		||||
sort * get_sort(expr const * n) {
 | 
			
		||||
    while (true) {
 | 
			
		||||
        switch(n->get_kind()) {
 | 
			
		||||
        case AST_APP:
 | 
			
		||||
            return to_app(n)->get_decl()->get_range();
 | 
			
		||||
        case AST_VAR:
 | 
			
		||||
            return to_var(n)->get_sort();
 | 
			
		||||
        case AST_QUANTIFIER:
 | 
			
		||||
            // The sort of the quantifier is the sort of the nested expression.
 | 
			
		||||
            // This code assumes the given expression is well-sorted.
 | 
			
		||||
            n = to_quantifier(n)->get_expr();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            UNREACHABLE();
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        }
 | 
			
		||||
    switch(n->get_kind()) {
 | 
			
		||||
    case AST_APP:
 | 
			
		||||
        return to_app(n)->get_decl()->get_range();
 | 
			
		||||
    case AST_VAR:
 | 
			
		||||
        return to_var(n)->get_sort();
 | 
			
		||||
    case AST_QUANTIFIER:
 | 
			
		||||
        return to_quantifier(n)->get_sort();
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -466,7 +484,7 @@ bool compare_nodes(ast const * n1, ast const * n2) {
 | 
			
		|||
            to_var(n1)->get_sort() == to_var(n2)->get_sort();
 | 
			
		||||
    case AST_QUANTIFIER:
 | 
			
		||||
        return
 | 
			
		||||
            to_quantifier(n1)->is_forall()           == to_quantifier(n2)->is_forall() &&
 | 
			
		||||
            to_quantifier(n1)->get_kind()            == to_quantifier(n2)->get_kind() &&
 | 
			
		||||
            to_quantifier(n1)->get_num_decls()       == to_quantifier(n2)->get_num_decls() &&
 | 
			
		||||
            compare_arrays(to_quantifier(n1)->get_decl_sorts(),
 | 
			
		||||
                           to_quantifier(n2)->get_decl_sorts(),
 | 
			
		||||
| 
						 | 
				
			
			@ -566,7 +584,7 @@ unsigned get_node_hash(ast const * n) {
 | 
			
		|||
    case AST_QUANTIFIER:
 | 
			
		||||
        a = ast_array_hash(to_quantifier(n)->get_decl_sorts(),
 | 
			
		||||
                           to_quantifier(n)->get_num_decls(),
 | 
			
		||||
                           to_quantifier(n)->is_forall() ? 31 : 19);
 | 
			
		||||
                           to_quantifier(n)->get_kind() == forall_k ? 31 : 19);
 | 
			
		||||
        b = to_quantifier(n)->get_num_patterns();
 | 
			
		||||
        c = to_quantifier(n)->get_expr()->hash();
 | 
			
		||||
        mix(a,b,c);
 | 
			
		||||
| 
						 | 
				
			
			@ -689,7 +707,8 @@ bool basic_decl_plugin::check_proof_sorts(basic_op_kind k, unsigned arity, sort
 | 
			
		|||
        for (unsigned i = 0; i < arity - 1; i++)
 | 
			
		||||
            if (domain[i] != m_proof_sort)
 | 
			
		||||
                return false;
 | 
			
		||||
        return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort;
 | 
			
		||||
#define is_array(_x_) true
 | 
			
		||||
        return domain[arity-1] == m_bool_sort || domain[arity-1] == m_proof_sort || is_array(domain[arity-1]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -704,7 +723,8 @@ bool basic_decl_plugin::check_proof_args(basic_op_kind k, unsigned num_args, exp
 | 
			
		|||
                return false;
 | 
			
		||||
        return
 | 
			
		||||
            m_manager->get_sort(args[num_args - 1]) == m_bool_sort ||
 | 
			
		||||
            m_manager->get_sort(args[num_args - 1]) == m_proof_sort;
 | 
			
		||||
            m_manager->get_sort(args[num_args - 1]) == m_proof_sort || 
 | 
			
		||||
            is_lambda(args[num_args-1]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -818,6 +838,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_paren
 | 
			
		|||
    case PR_TRANSITIVITY_STAR:            return mk_proof_decl("trans*", k, num_parents, m_transitivity_star_decls);
 | 
			
		||||
    case PR_MONOTONICITY:                 return mk_proof_decl("monotonicity", k, num_parents, m_monotonicity_decls);
 | 
			
		||||
    case PR_QUANT_INTRO:                  return mk_proof_decl("quant-intro", k, 1, m_quant_intro_decl);
 | 
			
		||||
    case PR_BIND:                         UNREACHABLE();
 | 
			
		||||
    case PR_DISTRIBUTIVITY:               return mk_proof_decl("distributivity", k, num_parents, m_distributivity_decls);
 | 
			
		||||
    case PR_AND_ELIM:                     return mk_proof_decl("and-elim", k, 1, m_and_elim_decl);
 | 
			
		||||
    case PR_NOT_OR_ELIM:                  return mk_proof_decl("not-or-elim", k, 1, m_not_or_elim_decl);
 | 
			
		||||
| 
						 | 
				
			
			@ -1054,6 +1075,10 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
 | 
			
		|||
        // eq and oeq must have at least two arguments, they can have more since they are chainable
 | 
			
		||||
    case OP_EQ:      return arity >= 2 ? mk_eq_decl_core("=", OP_EQ, join(arity, domain), m_eq_decls) : nullptr;
 | 
			
		||||
    case OP_OEQ:     return arity >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(arity, domain), m_oeq_decls) : nullptr;
 | 
			
		||||
    case PR_BIND: {
 | 
			
		||||
        func_decl_info info(m_family_id, PR_BIND);
 | 
			
		||||
        return m_manager->mk_func_decl(symbol("proof-bind"), arity, domain, m_proof_sort, info);
 | 
			
		||||
    }
 | 
			
		||||
    case OP_DISTINCT: {
 | 
			
		||||
        func_decl_info info(m_family_id, OP_DISTINCT);
 | 
			
		||||
        info.set_pairwise();
 | 
			
		||||
| 
						 | 
				
			
			@ -1097,6 +1122,11 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
 | 
			
		|||
    case OP_OEQ:     return num_args >= 2 ? mk_eq_decl_core("~", OP_OEQ, join(num_args, args), m_oeq_decls) : nullptr;
 | 
			
		||||
    case OP_DISTINCT:
 | 
			
		||||
        return decl_plugin::mk_func_decl(k, num_parameters, parameters, num_args, args, range);
 | 
			
		||||
	case PR_BIND: {
 | 
			
		||||
            ptr_buffer<sort> sorts;
 | 
			
		||||
            for (unsigned i = 0; i < num_args; ++i) sorts.push_back(m_manager->get_sort(args[i]));
 | 
			
		||||
            return mk_func_decl(k, num_parameters, parameters, num_args, sorts.c_ptr(), range);
 | 
			
		||||
	}	
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1218,7 +1248,6 @@ func_decl * model_value_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para
 | 
			
		|||
                                                  unsigned arity, sort * const * domain, sort * range) {
 | 
			
		||||
    SASSERT(k == OP_MODEL_VALUE);
 | 
			
		||||
    if (arity != 0 || num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_ast() || !is_sort(parameters[1].get_ast())) {
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        m_manager->raise_exception("invalid model value");
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1290,7 +1319,8 @@ ast_manager::ast_manager(proof_gen_mode m, char const * trace_file, bool is_form
 | 
			
		|||
    m_proof_mode(m),
 | 
			
		||||
    m_trace_stream(nullptr),
 | 
			
		||||
    m_trace_stream_owner(false),
 | 
			
		||||
    m_rec_fun(":rec-fun") {
 | 
			
		||||
    m_rec_fun(":rec-fun"),
 | 
			
		||||
    m_lambda_def(":lambda-def") {
 | 
			
		||||
 | 
			
		||||
    if (trace_file) {
 | 
			
		||||
        m_trace_stream       = alloc(std::fstream, trace_file, std::ios_base::out);
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,7 +1342,8 @@ ast_manager::ast_manager(proof_gen_mode m, std::fstream * trace_stream, bool is_
 | 
			
		|||
    m_proof_mode(m),
 | 
			
		||||
    m_trace_stream(trace_stream),
 | 
			
		||||
    m_trace_stream_owner(false),
 | 
			
		||||
    m_rec_fun(":rec-fun") {
 | 
			
		||||
    m_rec_fun(":rec-fun"),
 | 
			
		||||
    m_lambda_def(":lambda-def") {
 | 
			
		||||
 | 
			
		||||
    if (!is_format_manager)
 | 
			
		||||
        m_format_manager = alloc(ast_manager, PGM_DISABLED, trace_stream, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -1508,7 +1539,6 @@ void ast_manager::raise_exception(char const * msg) {
 | 
			
		|||
    throw ast_exception(msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "ast/ast_translation.h"
 | 
			
		||||
 | 
			
		||||
void ast_manager::copy_families_plugins(ast_manager const & from) {
 | 
			
		||||
    TRACE("copy_families_plugins",
 | 
			
		||||
| 
						 | 
				
			
			@ -1761,6 +1791,7 @@ ast * ast_manager::register_node_core(ast * n) {
 | 
			
		|||
    case AST_QUANTIFIER:
 | 
			
		||||
        inc_array_ref(to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
 | 
			
		||||
        inc_ref(to_quantifier(n)->get_expr());
 | 
			
		||||
        inc_ref(to_quantifier(n)->get_sort());
 | 
			
		||||
        inc_array_ref(to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
 | 
			
		||||
        inc_array_ref(to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1824,6 +1855,7 @@ void ast_manager::delete_node(ast * n) {
 | 
			
		|||
        case AST_QUANTIFIER:
 | 
			
		||||
            dec_array_ref(worklist, to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
 | 
			
		||||
            dec_ref(worklist, to_quantifier(n)->get_expr());
 | 
			
		||||
            dec_ref(worklist, to_quantifier(n)->get_sort());
 | 
			
		||||
            dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
 | 
			
		||||
            dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -2338,7 +2370,7 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector<expr> &args) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
 | 
			
		||||
quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names,
 | 
			
		||||
                                        expr * body, int weight , symbol const & qid, symbol const & skid,
 | 
			
		||||
                                        unsigned num_patterns, expr * const * patterns,
 | 
			
		||||
                                        unsigned num_no_patterns, expr * const * no_patterns) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2353,7 +2385,17 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
 | 
			
		|||
            }});
 | 
			
		||||
    unsigned sz               = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns);
 | 
			
		||||
    void * mem                = allocate_node(sz);
 | 
			
		||||
    quantifier * new_node = new (mem) quantifier(forall, num_decls, decl_sorts, decl_names, body,
 | 
			
		||||
 | 
			
		||||
    sort* s = nullptr;
 | 
			
		||||
    if (k == lambda_k) {
 | 
			
		||||
        array_util autil(*this);
 | 
			
		||||
        s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        s = mk_bool_sort();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    quantifier * new_node = new (mem) quantifier(k, num_decls, decl_sorts, decl_names, body, s,
 | 
			
		||||
                                                 weight, qid, skid, num_patterns, patterns,
 | 
			
		||||
                                                 num_no_patterns, no_patterns);
 | 
			
		||||
    quantifier * r = register_node(new_node);
 | 
			
		||||
| 
						 | 
				
			
			@ -2370,6 +2412,18 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
 | 
			
		|||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quantifier * ast_manager::mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body) {
 | 
			
		||||
    SASSERT(body);
 | 
			
		||||
    unsigned sz               = quantifier::get_obj_size(num_decls, 0, 0);
 | 
			
		||||
    void * mem                = allocate_node(sz);
 | 
			
		||||
    array_util autil(*this);
 | 
			
		||||
    sort* s = autil.mk_array_sort(num_decls, decl_sorts, ::get_sort(body));
 | 
			
		||||
    quantifier * new_node = new (mem) quantifier(num_decls, decl_sorts, decl_names, body, s);
 | 
			
		||||
    quantifier * r = register_node(new_node);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Return true if the patterns of q are the given ones.
 | 
			
		||||
static bool same_patterns(quantifier * q, unsigned num_patterns, expr * const * patterns) {
 | 
			
		||||
    if (num_patterns != q->get_num_patterns())
 | 
			
		||||
| 
						 | 
				
			
			@ -2393,7 +2447,7 @@ static bool same_no_patterns(quantifier * q, unsigned num_no_patterns, expr * co
 | 
			
		|||
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body && same_patterns(q, num_patterns, patterns))
 | 
			
		||||
        return q;
 | 
			
		||||
    return mk_quantifier(q->is_forall(),
 | 
			
		||||
    return mk_quantifier(q->get_kind(),
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2410,7 +2464,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
 | 
			
		|||
quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_patterns, expr * const * patterns, unsigned num_no_patterns, expr * const * no_patterns, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body && same_patterns(q, num_patterns, patterns) && same_no_patterns(q, num_no_patterns, no_patterns))
 | 
			
		||||
        return q;
 | 
			
		||||
    return mk_quantifier(q->is_forall(),
 | 
			
		||||
    return mk_quantifier(q->get_kind(),
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2427,7 +2481,7 @@ quantifier * ast_manager::update_quantifier(quantifier * q, unsigned num_pattern
 | 
			
		|||
quantifier * ast_manager::update_quantifier(quantifier * q, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body)
 | 
			
		||||
        return q;
 | 
			
		||||
    return mk_quantifier(q->is_forall(),
 | 
			
		||||
    return mk_quantifier(q->get_kind(),
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2445,7 +2499,7 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
 | 
			
		|||
    if (q->get_weight() == w)
 | 
			
		||||
        return q;
 | 
			
		||||
    TRACE("update_quantifier_weight", tout << "#" << q->get_id() << " " << q->get_weight() << " -> " << w << "\n";);
 | 
			
		||||
    return mk_quantifier(q->is_forall(),
 | 
			
		||||
    return mk_quantifier(q->get_kind(),
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2459,10 +2513,10 @@ quantifier * ast_manager::update_quantifier_weight(quantifier * q, int w) {
 | 
			
		|||
                         q->get_no_patterns());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body && q->is_forall() == is_forall)
 | 
			
		||||
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, expr * body) {    
 | 
			
		||||
    if (q->get_expr() == body && q->get_kind() == k)
 | 
			
		||||
        return q;
 | 
			
		||||
    return mk_quantifier(is_forall,
 | 
			
		||||
    return mk_quantifier(k,
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2476,10 +2530,10 @@ quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, expr
 | 
			
		|||
                         q->get_no_patterns());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
quantifier * ast_manager::update_quantifier(quantifier * q, bool is_forall, unsigned num_patterns, expr * const * patterns, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body && q->is_forall() == is_forall && same_patterns(q, num_patterns, patterns))
 | 
			
		||||
quantifier * ast_manager::update_quantifier(quantifier * q, quantifier_kind k, unsigned num_patterns, expr * const * patterns, expr * body) {
 | 
			
		||||
    if (q->get_expr() == body && q->get_kind() == k && same_patterns(q, num_patterns, patterns))
 | 
			
		||||
        return q;
 | 
			
		||||
    return mk_quantifier(is_forall,
 | 
			
		||||
    return mk_quantifier(k,
 | 
			
		||||
                         q->get_num_decls(),
 | 
			
		||||
                         q->get_decl_sorts(),
 | 
			
		||||
                         q->get_decl_names(),
 | 
			
		||||
| 
						 | 
				
			
			@ -2786,11 +2840,17 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs,
 | 
			
		|||
    return mk_monotonicity(mk_func_decl(m_basic_family_id, OP_OEQ, 0, nullptr, 2, d), f1, f2, num_proofs, proofs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
proof * ast_manager::mk_bind_proof(quantifier * q, proof * p) {
 | 
			
		||||
    expr* b = mk_lambda(q->get_num_decls(), q->get_decl_sorts(), q->get_decl_names(), p);
 | 
			
		||||
    return mk_app(m_basic_family_id, PR_BIND, b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) {
 | 
			
		||||
    if (!p) return nullptr;
 | 
			
		||||
    SASSERT(q1->get_num_decls() == q2->get_num_decls());
 | 
			
		||||
    SASSERT(has_fact(p));
 | 
			
		||||
    SASSERT(is_eq(get_fact(p)));
 | 
			
		||||
	if (!p) return nullptr;
 | 
			
		||||
	SASSERT(q1->get_num_decls() == q2->get_num_decls());
 | 
			
		||||
	SASSERT(has_fact(p));
 | 
			
		||||
	SASSERT(is_eq(get_fact(p)) || is_lambda(get_fact(p)));
 | 
			
		||||
    return mk_app(m_basic_family_id, PR_QUANT_INTRO, p, mk_iff(q1, q2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -793,11 +793,18 @@ public:
 | 
			
		|||
//
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
 | 
			
		||||
enum quantifier_kind {
 | 
			
		||||
    forall_k,
 | 
			
		||||
    exists_k,
 | 
			
		||||
    lambda_k
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class quantifier : public expr {
 | 
			
		||||
    friend class ast_manager;
 | 
			
		||||
    bool                m_forall;
 | 
			
		||||
    quantifier_kind     m_kind;
 | 
			
		||||
    unsigned            m_num_decls;
 | 
			
		||||
    expr *              m_expr;
 | 
			
		||||
    sort *              m_sort;
 | 
			
		||||
    unsigned            m_depth;
 | 
			
		||||
    // extra fields
 | 
			
		||||
    int                 m_weight;
 | 
			
		||||
| 
						 | 
				
			
			@ -813,12 +820,18 @@ class quantifier : public expr {
 | 
			
		|||
        return sizeof(quantifier) + num_decls * (sizeof(sort *) + sizeof(symbol)) + (num_patterns + num_no_patterns) * sizeof(expr*);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
 | 
			
		||||
    quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* s,
 | 
			
		||||
               int weight, symbol const & qid, symbol const & skid, unsigned num_patterns, expr * const * patterns,
 | 
			
		||||
               unsigned num_no_patterns, expr * const * no_patterns);
 | 
			
		||||
 | 
			
		||||
    quantifier(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, sort* sort);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    bool is_forall() const { return m_forall; }
 | 
			
		||||
    bool is_exists() const { return !m_forall; }
 | 
			
		||||
    quantifier_kind get_kind() const { return m_kind; }
 | 
			
		||||
//    bool is_forall() const { return m_kind == forall_k; }
 | 
			
		||||
//    bool is_exists() const { return m_kind == exists_k; }
 | 
			
		||||
//    bool is_lambda() const { return m_kind == lambda_k; }
 | 
			
		||||
 | 
			
		||||
    unsigned get_num_decls() const { return m_num_decls; }
 | 
			
		||||
    sort * const * get_decl_sorts() const { return reinterpret_cast<sort * const *>(m_patterns_decls); }
 | 
			
		||||
    symbol const * get_decl_names() const { return reinterpret_cast<symbol const *>(get_decl_sorts() + m_num_decls); }
 | 
			
		||||
| 
						 | 
				
			
			@ -826,6 +839,8 @@ public:
 | 
			
		|||
    symbol const & get_decl_name(unsigned idx) const { return get_decl_names()[idx]; }
 | 
			
		||||
    expr * get_expr() const { return m_expr; }
 | 
			
		||||
 | 
			
		||||
    sort * get_sort() const { return m_sort; }
 | 
			
		||||
 | 
			
		||||
    unsigned get_depth() const { return m_depth; }
 | 
			
		||||
 | 
			
		||||
    int get_weight() const { return m_weight; }
 | 
			
		||||
| 
						 | 
				
			
			@ -845,6 +860,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    bool has_labels() const { return m_has_labels; }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    unsigned get_num_children() const { return 1 + get_num_patterns() + get_num_no_patterns(); }
 | 
			
		||||
    expr * get_child(unsigned idx) const {
 | 
			
		||||
        SASSERT(idx < get_num_children());
 | 
			
		||||
| 
						 | 
				
			
			@ -871,8 +887,9 @@ inline bool is_app(ast const * n)        { return n->get_kind() == AST_APP; }
 | 
			
		|||
inline bool is_var(ast const * n)        { return n->get_kind() == AST_VAR; }
 | 
			
		||||
inline bool is_var(ast const * n, unsigned& idx) { return is_var(n) && (idx = static_cast<var const*>(n)->get_idx(), true); }
 | 
			
		||||
inline bool is_quantifier(ast const * n) { return n->get_kind() == AST_QUANTIFIER; }
 | 
			
		||||
inline bool is_forall(ast const * n)     { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_forall(); }
 | 
			
		||||
inline bool is_exists(ast const * n)     { return is_quantifier(n) && static_cast<quantifier const *>(n)->is_exists(); }
 | 
			
		||||
inline bool is_forall(ast const * n)     { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == forall_k; }
 | 
			
		||||
inline bool is_exists(ast const * n)     { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == exists_k; }
 | 
			
		||||
inline bool is_lambda(ast const * n)     { return is_quantifier(n) && static_cast<quantifier const *>(n)->get_kind() == lambda_k; }
 | 
			
		||||
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -950,7 +967,7 @@ protected:
 | 
			
		|||
    family_id     m_family_id;
 | 
			
		||||
 | 
			
		||||
    virtual void set_manager(ast_manager * m, family_id id) {
 | 
			
		||||
        SASSERT(m_manager == 0);
 | 
			
		||||
        SASSERT(m_manager == nullptr);
 | 
			
		||||
        m_manager   = m;
 | 
			
		||||
        m_family_id = id;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,7 +1060,7 @@ enum basic_sort_kind {
 | 
			
		|||
enum basic_op_kind {
 | 
			
		||||
    OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP,
 | 
			
		||||
 | 
			
		||||
    PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO,
 | 
			
		||||
    PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_BIND,
 | 
			
		||||
    PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT,
 | 
			
		||||
    PR_PUSH_QUANT, PR_ELIM_UNUSED_VARS, PR_DER, PR_QUANT_INST,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1487,6 +1504,7 @@ protected:
 | 
			
		|||
#endif
 | 
			
		||||
    ast_manager *             m_format_manager; // hack for isolating format objects in a different manager.
 | 
			
		||||
    symbol                    m_rec_fun;
 | 
			
		||||
    symbol                    m_lambda_def;
 | 
			
		||||
 | 
			
		||||
    void init();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1594,9 +1612,12 @@ public:
 | 
			
		|||
    bool contains(ast * a) const { return m_ast_table.contains(a); }
 | 
			
		||||
 | 
			
		||||
    bool is_rec_fun_def(quantifier* q) const { return q->get_qid() == m_rec_fun; }
 | 
			
		||||
    bool is_lambda_def(quantifier* q) const { return q->get_qid() == m_lambda_def; }
 | 
			
		||||
    
 | 
			
		||||
    symbol const& rec_fun_qid() const { return m_rec_fun; }
 | 
			
		||||
 | 
			
		||||
    symbol const& lambda_def_qid() const { return m_lambda_def; }
 | 
			
		||||
 | 
			
		||||
    unsigned get_num_asts() const { return m_ast_table.size(); }
 | 
			
		||||
 | 
			
		||||
    void debug_ref_count() { m_debug_ref_count = true; }
 | 
			
		||||
| 
						 | 
				
			
			@ -1892,7 +1913,7 @@ public:
 | 
			
		|||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    quantifier * mk_quantifier(bool forall, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body,
 | 
			
		||||
    quantifier * mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, 
 | 
			
		||||
                               int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
 | 
			
		||||
                               unsigned num_patterns = 0, expr * const * patterns = nullptr,
 | 
			
		||||
                               unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1901,7 +1922,7 @@ public:
 | 
			
		|||
                           int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
 | 
			
		||||
                           unsigned num_patterns = 0, expr * const * patterns = nullptr,
 | 
			
		||||
                           unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
 | 
			
		||||
        return mk_quantifier(true, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
 | 
			
		||||
        return mk_quantifier(forall_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
 | 
			
		||||
                             num_no_patterns, no_patterns);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1909,10 +1930,12 @@ public:
 | 
			
		|||
                           int weight = 0, symbol const & qid = symbol::null, symbol const & skid = symbol::null,
 | 
			
		||||
                           unsigned num_patterns = 0, expr * const * patterns = nullptr,
 | 
			
		||||
                           unsigned num_no_patterns = 0, expr * const * no_patterns = nullptr) {
 | 
			
		||||
        return mk_quantifier(false, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
 | 
			
		||||
        return mk_quantifier(exists_k, num_decls, decl_sorts, decl_names, body, weight, qid, skid, num_patterns, patterns,
 | 
			
		||||
                             num_no_patterns, no_patterns);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    quantifier * mk_lambda(unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body);
 | 
			
		||||
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
 | 
			
		||||
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, unsigned new_num_patterns, expr * const * new_patterns, unsigned new_num_no_patterns, expr * const * new_no_patterns, expr * new_body);
 | 
			
		||||
| 
						 | 
				
			
			@ -1921,9 +1944,9 @@ public:
 | 
			
		|||
 | 
			
		||||
    quantifier * update_quantifier_weight(quantifier * q, int new_weight);
 | 
			
		||||
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, bool new_is_forall, expr * new_body);
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, expr * new_body);
 | 
			
		||||
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, bool new_is_forall, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
 | 
			
		||||
    quantifier * update_quantifier(quantifier * q, quantifier_kind new_kind, unsigned new_num_patterns, expr * const * new_patterns, expr * new_body);
 | 
			
		||||
 | 
			
		||||
// -----------------------------------
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -2213,6 +2236,7 @@ public:
 | 
			
		|||
    proof * mk_rewrite(expr * s, expr * t);
 | 
			
		||||
    proof * mk_oeq_rewrite(expr * s, expr * t);
 | 
			
		||||
    proof * mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs);
 | 
			
		||||
    proof * mk_bind_proof(quantifier * q, proof * p);
 | 
			
		||||
    proof * mk_pull_quant(expr * e, quantifier * q);
 | 
			
		||||
    proof * mk_push_quant(quantifier * q, expr * e);
 | 
			
		||||
    proof * mk_elim_unused_vars(quantifier * q, expr * r);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -242,7 +242,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void operator()(quantifier * n) {
 | 
			
		||||
        display_def_header(n);
 | 
			
		||||
        m_out << "(" << (n->is_forall() ? "forall" : "exists") << " ";
 | 
			
		||||
        m_out << "(" << (n->get_kind() == forall_k ? "forall" : (n->get_kind() == exists_k ? "exists" : "lambda")) << " ";
 | 
			
		||||
        unsigned num_decls = n->get_num_decls();
 | 
			
		||||
        m_out << "(vars ";
 | 
			
		||||
        for (unsigned i = 0; i < num_decls; i++) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,7 +102,7 @@ bool lt(ast * n1, ast * n2) {
 | 
			
		|||
        UNREACHABLE();
 | 
			
		||||
        return false;
 | 
			
		||||
    case AST_QUANTIFIER:
 | 
			
		||||
        check_bool(to_quantifier(n1)->is_forall(), to_quantifier(n2)->is_forall());
 | 
			
		||||
        check_value(to_quantifier(n1)->get_kind(), to_quantifier(n2)->get_kind());
 | 
			
		||||
        check_value(to_quantifier(n1)->get_num_decls(), to_quantifier(n2)->get_num_decls());
 | 
			
		||||
        check_value(to_quantifier(n1)->get_num_patterns(), to_quantifier(n2)->get_num_patterns());
 | 
			
		||||
        check_value(to_quantifier(n1)->get_num_no_patterns(), to_quantifier(n2)->get_num_no_patterns());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -994,7 +994,7 @@ class smt2_printer {
 | 
			
		|||
        }
 | 
			
		||||
        format * f_decls = pp_var_decls(q);
 | 
			
		||||
        format * fs[2] = { f_decls, f_body };
 | 
			
		||||
        char const * header = q->is_forall() ? "forall" : "exists";
 | 
			
		||||
        char const * header = q->get_kind() == forall_k ? "forall" : (q->get_kind() == exists_k ? "exists" : "lambda");
 | 
			
		||||
        format * f = mk_seq3<format**, f2f>(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT);
 | 
			
		||||
 | 
			
		||||
        info f_info = m_info_stack.back();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -495,11 +495,10 @@ class smt_printer {
 | 
			
		|||
        m_qlists.push_back(q);
 | 
			
		||||
 | 
			
		||||
        m_out << "(";
 | 
			
		||||
        if (q->is_forall()) {
 | 
			
		||||
            m_out << "forall ";
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_out << "exists ";
 | 
			
		||||
        switch (q->get_kind()) {
 | 
			
		||||
        case forall_k: m_out << "forall "; break;
 | 
			
		||||
        case exists_k: m_out << "exists "; break;
 | 
			
		||||
        case lambda_k: m_out << "lambda "; break;
 | 
			
		||||
        }
 | 
			
		||||
        m_out << "(";
 | 
			
		||||
        for (unsigned i = 0; i < q->get_num_decls(); ++i) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -279,7 +279,7 @@ ast * ast_translation::process(ast const * _n) {
 | 
			
		|||
                expr **  pats         = reinterpret_cast<expr**>(m_result_stack.c_ptr() + fr.m_rpos + num_decls + 1);
 | 
			
		||||
                unsigned num_no_pats  = to_quantifier(n)->get_num_no_patterns();
 | 
			
		||||
                expr **  no_pats      = pats + num_pats;
 | 
			
		||||
                quantifier * new_q    = m_to_manager.mk_quantifier(to_quantifier(n)->is_forall(),
 | 
			
		||||
                quantifier * new_q    = m_to_manager.mk_quantifier(to_quantifier(n)->get_kind(),
 | 
			
		||||
                                                                   num_decls,
 | 
			
		||||
                                                                   dsorts,
 | 
			
		||||
                                                                   dnames,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,7 +115,7 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
 | 
			
		|||
          tout << result << "\n";);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
 | 
			
		||||
expr_ref mk_quantifier(quantifier_kind k, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
 | 
			
		||||
    expr_ref result(m);
 | 
			
		||||
    expr_abstract(m, 0, num_bound, (expr* const*)bound, n, result);    
 | 
			
		||||
    if (num_bound > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
 | 
			
		|||
            sorts.push_back(m.get_sort(bound[i]));
 | 
			
		||||
            names.push_back(bound[i]->get_decl()->get_name());
 | 
			
		||||
        }
 | 
			
		||||
        result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result);
 | 
			
		||||
        result = m.mk_quantifier(k, num_bound, sorts.c_ptr(), names.c_ptr(), result);
 | 
			
		||||
    }
 | 
			
		||||
    TRACE("expr_abstract",
 | 
			
		||||
          tout << expr_ref(n, m) << "\n";
 | 
			
		||||
| 
						 | 
				
			
			@ -137,9 +137,9 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app*
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
expr_ref mk_forall(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
 | 
			
		||||
    return mk_quantifier(true, m, num_bound, bound, n);
 | 
			
		||||
    return mk_quantifier(forall_k, m, num_bound, bound, n);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref mk_exists(ast_manager& m, unsigned num_bound, app* const* bound, expr* n) {
 | 
			
		||||
    return mk_quantifier(false, m, num_bound, bound, n);
 | 
			
		||||
    return mk_quantifier(exists_k, m, num_bound, bound, n);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -194,6 +194,9 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
 | 
			
		|||
                           expr * const * new_no_patterns,
 | 
			
		||||
                           expr_ref & result,
 | 
			
		||||
                           proof_ref & result_pr) {
 | 
			
		||||
    if (is_lambda(old_q)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    unsigned curr_sz   = m_bindings.size();
 | 
			
		||||
    SASSERT(old_q->get_num_decls() <= curr_sz);
 | 
			
		||||
    unsigned num_decls = old_q->get_num_decls();
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +220,7 @@ bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q,
 | 
			
		|||
            new_decl_names.push_back(n);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
 | 
			
		||||
    result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
 | 
			
		||||
                               new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
 | 
			
		||||
                               old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
 | 
			
		||||
    result_pr = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ Revision History:
 | 
			
		|||
#include "ast/ast_ll_pp.h"
 | 
			
		||||
 | 
			
		||||
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
 | 
			
		||||
    if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
 | 
			
		||||
    if (!is_forall(n))
 | 
			
		||||
        return false;
 | 
			
		||||
    TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
 | 
			
		||||
    expr * body        = to_quantifier(n)->get_expr();
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
 | 
			
		|||
   For case 2 & 3, the new quantifiers are stored in new_exprs and new_prs.
 | 
			
		||||
*/
 | 
			
		||||
bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
 | 
			
		||||
    if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
 | 
			
		||||
    if (!is_forall(n))
 | 
			
		||||
        return false;
 | 
			
		||||
    expr * body        = to_quantifier(n)->get_expr();
 | 
			
		||||
    unsigned num_decls = to_quantifier(n)->get_num_decls();
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, e
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) {
 | 
			
		||||
    if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
 | 
			
		||||
    if (!is_forall(n))
 | 
			
		||||
        return false;
 | 
			
		||||
    expr * body        = to_quantifier(n)->get_expr();
 | 
			
		||||
    unsigned num_decls = to_quantifier(n)->get_num_decls();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -283,13 +283,11 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
 | 
			
		|||
                subst_args[nidx] = n->get_arg(i);
 | 
			
		||||
            }
 | 
			
		||||
            var_subst s(m);
 | 
			
		||||
            expr_ref rr(m);
 | 
			
		||||
            s(def, num, subst_args.c_ptr(), rr);
 | 
			
		||||
            expr_ref rr = s(def, num, subst_args.c_ptr());
 | 
			
		||||
            m_trail.push_back(rr);
 | 
			
		||||
            r = rr;
 | 
			
		||||
            if (m.proofs_enabled()) {
 | 
			
		||||
                expr_ref instance(m);
 | 
			
		||||
                s(q->get_expr(), num, subst_args.c_ptr(), instance);
 | 
			
		||||
                expr_ref instance = s(q->get_expr(), num, subst_args.c_ptr());
 | 
			
		||||
                proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
 | 
			
		||||
                proof * q_pr  = nullptr;
 | 
			
		||||
                mm.m_decl2macro_pr.find(d, q_pr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -334,7 +334,7 @@ bool macro_util::is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, ap
 | 
			
		|||
   where t is a ground term, (f X) is the head.
 | 
			
		||||
*/
 | 
			
		||||
bool macro_util::is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def) {
 | 
			
		||||
    if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
 | 
			
		||||
    if (!is_forall(n)) 
 | 
			
		||||
        return false;
 | 
			
		||||
    TRACE("macro_util", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
 | 
			
		||||
    expr * body        = to_quantifier(n)->get_expr();
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +485,7 @@ void macro_util::normalize_expr(app * head, unsigned num_decls, expr * t, expr_r
 | 
			
		|||
                  if (var_mapping[i] != 0)
 | 
			
		||||
                      tout << "#" << i << " -> " << mk_ll_pp(var_mapping[i], m_manager);
 | 
			
		||||
              });
 | 
			
		||||
        subst(t, var_mapping.size(), var_mapping.c_ptr(), norm_t);
 | 
			
		||||
        norm_t = subst(t, var_mapping.size(), var_mapping.c_ptr());
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        norm_t = t;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,7 +155,7 @@ bool quasi_macros::is_quasi_macro(expr * e, app_ref & a, expr_ref & t) const {
 | 
			
		|||
    // f[X] contains all universally quantified variables, and f does not occur in T[X].
 | 
			
		||||
    TRACE("quasi_macros", tout << "Checking for quasi macro: " << mk_pp(e, m_manager) << std::endl;);
 | 
			
		||||
 | 
			
		||||
    if (is_quantifier(e) && to_quantifier(e)->is_forall()) {
 | 
			
		||||
    if (is_forall(e)) {
 | 
			
		||||
        quantifier * q = to_quantifier(e);
 | 
			
		||||
        expr * qe = q->get_expr();
 | 
			
		||||
        if ((m_manager.is_eq(qe))) {
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +251,7 @@ void quasi_macros::quasi_macro_to_macro(quantifier * q, app * a, expr * t, quant
 | 
			
		|||
 | 
			
		||||
    eq = m_manager.mk_eq(appl, ite);
 | 
			
		||||
 | 
			
		||||
    macro = m_manager.mk_quantifier(true, new_var_names_rev.size(),
 | 
			
		||||
    macro = m_manager.mk_quantifier(forall_k, new_var_names_rev.size(),
 | 
			
		||||
                                    new_qsorts_rev.c_ptr(), new_var_names_rev.c_ptr(), eq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,17 +16,19 @@ Author:
 | 
			
		|||
Revision History:
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "ast/normal_forms/defined_names.h"
 | 
			
		||||
#include "util/obj_hashtable.h"
 | 
			
		||||
#include "ast/normal_forms/defined_names.h"
 | 
			
		||||
#include "ast/used_vars.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/ast_smt2_pp.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/ast_util.h"
 | 
			
		||||
#include "ast/array_decl_plugin.h"
 | 
			
		||||
 | 
			
		||||
struct defined_names::impl {
 | 
			
		||||
    typedef obj_map<expr, app *>   expr2name;
 | 
			
		||||
    typedef obj_map<expr, proof *> expr2proof;
 | 
			
		||||
    ast_manager &    m_manager;
 | 
			
		||||
    ast_manager &    m;
 | 
			
		||||
    symbol           m_z3name;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -60,9 +62,9 @@ struct defined_names::impl {
 | 
			
		|||
    app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names);
 | 
			
		||||
    void cache_new_name(expr * e, app * name);
 | 
			
		||||
    void cache_new_name_intro_proof(expr * e, proof * pr);
 | 
			
		||||
    void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result);
 | 
			
		||||
    void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result);
 | 
			
		||||
    virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def);
 | 
			
		||||
    void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid = symbol::null);
 | 
			
		||||
    void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid = symbol::null);
 | 
			
		||||
    virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def);
 | 
			
		||||
    bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
 | 
			
		||||
    void push_scope();
 | 
			
		||||
    void pop_scope(unsigned num_scopes);
 | 
			
		||||
| 
						 | 
				
			
			@ -74,12 +76,13 @@ struct defined_names::impl {
 | 
			
		|||
 | 
			
		||||
struct defined_names::pos_impl : public defined_names::impl {
 | 
			
		||||
    pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {}
 | 
			
		||||
    void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) override;
 | 
			
		||||
    void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) override;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
defined_names::impl::impl(ast_manager & m, char const * prefix):
 | 
			
		||||
    m_manager(m),
 | 
			
		||||
    m(m),
 | 
			
		||||
    m_exprs(m),
 | 
			
		||||
    m_names(m),
 | 
			
		||||
    m_apply_proofs(m) {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,20 +110,20 @@ app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffe
 | 
			
		|||
        sort * s = uv.get(i);
 | 
			
		||||
        if (s) {
 | 
			
		||||
            domain.push_back(s);
 | 
			
		||||
            new_args.push_back(m_manager.mk_var(i, s));
 | 
			
		||||
            new_args.push_back(m.mk_var(i, s));
 | 
			
		||||
            var_sorts.push_back(s);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            var_sorts.push_back(m_manager.mk_bool_sort()); // could be any sort.
 | 
			
		||||
            var_sorts.push_back(m.mk_bool_sort()); // could be any sort.
 | 
			
		||||
        }
 | 
			
		||||
        var_names.push_back(symbol(i));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sort * range = m_manager.get_sort(e);
 | 
			
		||||
    func_decl * new_skolem_decl = m_manager.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
 | 
			
		||||
    app * n = m_manager.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
 | 
			
		||||
    TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m_manager) << "\n";
 | 
			
		||||
          for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m_manager) << " ";
 | 
			
		||||
    sort * range = m.get_sort(e);
 | 
			
		||||
    func_decl * new_skolem_decl = m.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
 | 
			
		||||
    app * n = m.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
 | 
			
		||||
    TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m) << "\n";
 | 
			
		||||
          for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m) << " ";
 | 
			
		||||
          tout << "\n";);
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -148,22 +151,22 @@ void defined_names::impl::cache_new_name_intro_proof(expr * e, proof * pr) {
 | 
			
		|||
   A quantifier is added around \c def_conjunct, if sorts and names are not empty.
 | 
			
		||||
   In this case, The application \c name is used as a pattern for the new quantifier.
 | 
			
		||||
*/
 | 
			
		||||
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result) {
 | 
			
		||||
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid) {
 | 
			
		||||
    SASSERT(sorts.size() == names.size());
 | 
			
		||||
    if (sorts.empty())
 | 
			
		||||
        result = def_conjunct;
 | 
			
		||||
    else {
 | 
			
		||||
        expr * patterns[1] = { m_manager.mk_pattern(name) };
 | 
			
		||||
        quantifier_ref q(m_manager);
 | 
			
		||||
        q = m_manager.mk_forall(sorts.size(),
 | 
			
		||||
        expr * patterns[1] = { m.mk_pattern(name) };
 | 
			
		||||
        quantifier_ref q(m);
 | 
			
		||||
        q = m.mk_forall(sorts.size(),
 | 
			
		||||
                                sorts.c_ptr(),
 | 
			
		||||
                                names.c_ptr(),
 | 
			
		||||
                                def_conjunct,
 | 
			
		||||
                                1, symbol::null, symbol::null,
 | 
			
		||||
                                1, qid, symbol::null,
 | 
			
		||||
                                1, patterns);
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m_manager) << "\n";);
 | 
			
		||||
        elim_unused_vars(m_manager, q, params_ref(), result);
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m_manager) << "\n";);
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m) << "\n";);
 | 
			
		||||
        result = elim_unused_vars(m, q, params_ref());
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << result << "\n";);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -172,44 +175,81 @@ void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbo
 | 
			
		|||
   A quantifier is added around \c def_conjunct, if sorts and names are not empty.
 | 
			
		||||
   In this case, The application \c name is used as a pattern for the new quantifier.
 | 
			
		||||
*/
 | 
			
		||||
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result) {
 | 
			
		||||
    expr_ref tmp(m_manager);
 | 
			
		||||
    bound_vars(sorts, names, def_conjunct, name, tmp);
 | 
			
		||||
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result, symbol const& qid) {
 | 
			
		||||
    expr_ref tmp(m);
 | 
			
		||||
    bound_vars(sorts, names, def_conjunct, name, tmp, qid);
 | 
			
		||||
    result.push_back(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MK_OR      m_manager.mk_or
 | 
			
		||||
#define MK_NOT     m_manager.mk_not
 | 
			
		||||
#define MK_EQ      m_manager.mk_eq
 | 
			
		||||
#define MK_OR      m.mk_or
 | 
			
		||||
#define MK_NOT     m.mk_not
 | 
			
		||||
#define MK_EQ      m.mk_eq
 | 
			
		||||
 | 
			
		||||
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
 | 
			
		||||
    expr_ref_buffer defs(m_manager);
 | 
			
		||||
    if (m_manager.is_bool(e)) {
 | 
			
		||||
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
 | 
			
		||||
    expr_ref_buffer defs(m);
 | 
			
		||||
    if (m.is_bool(e)) {
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, defs);
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_OR(n, MK_NOT(e)), n, defs);
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_manager.is_term_ite(e)) {
 | 
			
		||||
    else if (m.is_term_ite(e)) {
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0),         MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
 | 
			
		||||
    }
 | 
			
		||||
    else if (is_lambda(e)) {
 | 
			
		||||
        //    n(y) = \x . M[x,y]
 | 
			
		||||
        // => 
 | 
			
		||||
        //    n(y)[x] = M,  forall x y
 | 
			
		||||
        // 
 | 
			
		||||
        // NB. The pattern is incomplete.
 | 
			
		||||
        // consider store(a, i, v) == \lambda j . if i = j then v else a[j]
 | 
			
		||||
        // the instantiation rules for store(a, i, v) are:
 | 
			
		||||
        //     sotre(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
 | 
			
		||||
        // The first pattern is not included.
 | 
			
		||||
        // TBD use a model-based scheme for exracting instantiations instead of
 | 
			
		||||
        // using multi-patterns.
 | 
			
		||||
        // 
 | 
			
		||||
 | 
			
		||||
        quantifier* q = to_quantifier(e);
 | 
			
		||||
        expr_ref_vector args(m);
 | 
			
		||||
        expr_ref n2(m), n3(m);
 | 
			
		||||
        var_shifter vs(m);
 | 
			
		||||
        vs(n, q->get_num_decls(), n2);        
 | 
			
		||||
        args.push_back(n2);
 | 
			
		||||
        var_sorts.append(q->get_num_decls(), q->get_decl_sorts());
 | 
			
		||||
        var_names.append(q->get_num_decls(), q->get_decl_names());
 | 
			
		||||
        for (unsigned i = 0; i < q->get_num_decls(); ++i) {
 | 
			
		||||
            args.push_back(m.mk_var(q->get_num_decls() - i - 1, q->get_decl_sort(i)));
 | 
			
		||||
        }
 | 
			
		||||
        array_util autil(m);
 | 
			
		||||
        func_decl * f = 0;
 | 
			
		||||
        if (autil.is_as_array(n2, f)) {
 | 
			
		||||
            n3 = m.mk_app(f, args.size()-1, args.c_ptr() + 1);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            n3 = autil.mk_select(args.size(), args.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_EQ(q->get_expr(), n3), to_app(n3), defs, m.lambda_def_qid());
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
 | 
			
		||||
    }
 | 
			
		||||
    new_def = defs.size() == 1 ? defs[0] : m_manager.mk_and(defs.size(), defs.c_ptr());
 | 
			
		||||
    new_def = mk_and(m, defs.size(), defs.c_ptr());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
 | 
			
		||||
 | 
			
		||||
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> & var_names, expr_ref & new_def) {
 | 
			
		||||
    bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, new_def);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
 | 
			
		||||
    TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m_manager) << "\n";);
 | 
			
		||||
    TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m) << "\n";);
 | 
			
		||||
 | 
			
		||||
    app *   n_ptr;
 | 
			
		||||
    if (m_expr2name.find(e, n_ptr)) {
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
 | 
			
		||||
        n = n_ptr;
 | 
			
		||||
        if (m_manager.proofs_enabled()) {
 | 
			
		||||
        if (m.proofs_enabled()) {
 | 
			
		||||
            proof * pr_ptr = nullptr;
 | 
			
		||||
            m_expr2proof.find(e, pr_ptr);
 | 
			
		||||
            SASSERT(pr_ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -218,24 +258,24 @@ bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        sort_ref_buffer  var_sorts(m_manager);
 | 
			
		||||
        sort_ref_buffer  var_sorts(m);
 | 
			
		||||
        buffer<symbol>   var_names;
 | 
			
		||||
 | 
			
		||||
        n = gen_name(e, var_sorts, var_names);
 | 
			
		||||
        cache_new_name(e, n);
 | 
			
		||||
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m_manager) << "\n";);
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m) << "\n";);
 | 
			
		||||
        // variables are in reverse order in quantifiers
 | 
			
		||||
        std::reverse(var_sorts.c_ptr(), var_sorts.c_ptr() + var_sorts.size());
 | 
			
		||||
        std::reverse(var_names.c_ptr(), var_names.c_ptr() + var_names.size());
 | 
			
		||||
 | 
			
		||||
        mk_definition(e, n, var_sorts, var_names, new_def);
 | 
			
		||||
 | 
			
		||||
       TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m_manager) << "\n";);
 | 
			
		||||
        TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m) << "\n";);
 | 
			
		||||
 | 
			
		||||
        if (m_manager.proofs_enabled()) {
 | 
			
		||||
            new_def_pr = m_manager.mk_def_intro(new_def);
 | 
			
		||||
            pr         = m_manager.mk_apply_def(e, n, new_def_pr);
 | 
			
		||||
        if (m.proofs_enabled()) {
 | 
			
		||||
            new_def_pr = m.mk_def_intro(new_def);
 | 
			
		||||
            pr         = m.mk_apply_def(e, n, new_def_pr);
 | 
			
		||||
            cache_new_name_intro_proof(e, pr);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +297,7 @@ void defined_names::impl::pop_scope(unsigned num_scopes) {
 | 
			
		|||
    SASSERT(sz == m_names.size());
 | 
			
		||||
    while (old_sz != sz) {
 | 
			
		||||
        --sz;
 | 
			
		||||
        if (m_manager.proofs_enabled()) {
 | 
			
		||||
        if (m.proofs_enabled()) {
 | 
			
		||||
            m_expr2proof.erase(m_exprs.back());
 | 
			
		||||
            m_apply_proofs.pop_back();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +336,15 @@ bool defined_names::mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_de
 | 
			
		|||
    return m_pos_impl->mk_name(e, new_def, new_def_pr, n, pr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref defined_names::mk_definition(expr * e, app * n) {
 | 
			
		||||
    ast_manager& m = m_impl->m;
 | 
			
		||||
    sort_ref_buffer  var_sorts(m);
 | 
			
		||||
    expr_ref new_def(m);
 | 
			
		||||
    buffer<symbol>   var_names;
 | 
			
		||||
    m_impl->mk_definition(e, n, var_sorts, var_names, new_def);
 | 
			
		||||
    return new_def;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void defined_names::push() {
 | 
			
		||||
    m_impl->push_scope();
 | 
			
		||||
    m_pos_impl->push_scope();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,11 @@ public:
 | 
			
		|||
    */
 | 
			
		||||
    bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Create a definition for 'n' using 'e'.
 | 
			
		||||
     */
 | 
			
		||||
    expr_ref mk_definition(expr * e, app * n);
 | 
			
		||||
 | 
			
		||||
    void push();
 | 
			
		||||
    void pop(unsigned num_scopes);
 | 
			
		||||
    void reset();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ Notes:
 | 
			
		|||
 | 
			
		||||
class name_exprs_core : public name_exprs {
 | 
			
		||||
    struct cfg : public default_rewriter_cfg {
 | 
			
		||||
        ast_manager &           m_manager;
 | 
			
		||||
        ast_manager &           m;
 | 
			
		||||
        defined_names &         m_defined_names;
 | 
			
		||||
        expr_predicate &        m_pred;
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ class name_exprs_core : public name_exprs {
 | 
			
		|||
        proof_ref_vector *      m_def_proofs;
 | 
			
		||||
 | 
			
		||||
        cfg(ast_manager & m, defined_names & n, expr_predicate & pred):
 | 
			
		||||
            m_manager(m),
 | 
			
		||||
            m(m),
 | 
			
		||||
            m_defined_names(n),
 | 
			
		||||
            m_pred(pred),
 | 
			
		||||
            m_r(m),
 | 
			
		||||
| 
						 | 
				
			
			@ -43,12 +43,12 @@ class name_exprs_core : public name_exprs {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        void gen_name_for_expr(expr * n, expr * & t, proof * & t_pr) {
 | 
			
		||||
            expr_ref  new_def(m_manager);
 | 
			
		||||
            proof_ref new_def_pr(m_manager);
 | 
			
		||||
            expr_ref  new_def(m);
 | 
			
		||||
            proof_ref new_def_pr(m);
 | 
			
		||||
            
 | 
			
		||||
            if (m_defined_names.mk_name(n, new_def, new_def_pr, m_r, m_pr)) {
 | 
			
		||||
                m_def_exprs->push_back(new_def);
 | 
			
		||||
                if (m_manager.proofs_enabled())
 | 
			
		||||
                if (m.proofs_enabled())
 | 
			
		||||
                    m_def_proofs->push_back(new_def_pr);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ class name_exprs_core : public name_exprs {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        bool get_subst(expr * s, expr * & t, proof * & t_pr) {
 | 
			
		||||
            TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m_manager) << "\n";);
 | 
			
		||||
            TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m) << "\n";);
 | 
			
		||||
            if (m_pred(s)) {
 | 
			
		||||
                gen_name_for_expr(s, t, t_pr);
 | 
			
		||||
                return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ public:
 | 
			
		|||
        m_cfg.m_def_exprs  = &new_defs;
 | 
			
		||||
        m_cfg.m_def_proofs = &new_def_proofs;
 | 
			
		||||
        m_rw(n, r, p);
 | 
			
		||||
        TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << mk_ismt2_pp(r, m_rw.m()) << "\n";);
 | 
			
		||||
        TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << r << "\n";);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,11 +99,11 @@ name_exprs * mk_expr_namer(ast_manager & m, defined_names & n, expr_predicate &
 | 
			
		|||
 | 
			
		||||
class name_quantifier_labels : public name_exprs_core {
 | 
			
		||||
    class pred : public expr_predicate {
 | 
			
		||||
        ast_manager & m_manager;
 | 
			
		||||
        ast_manager & m;
 | 
			
		||||
    public:
 | 
			
		||||
        pred(ast_manager & m):m_manager(m) {}
 | 
			
		||||
        pred(ast_manager & m):m(m) {}
 | 
			
		||||
        bool operator()(expr * t) override {
 | 
			
		||||
            return is_quantifier(t) || m_manager.is_label(t);
 | 
			
		||||
            return is_quantifier(t) || m.is_label(t);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -124,16 +124,16 @@ name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n) {
 | 
			
		|||
 | 
			
		||||
class name_nested_formulas : public name_exprs_core {
 | 
			
		||||
    struct pred : public expr_predicate {
 | 
			
		||||
        ast_manager & m_manager;
 | 
			
		||||
        ast_manager & m;
 | 
			
		||||
        expr *        m_root;
 | 
			
		||||
 | 
			
		||||
        pred(ast_manager & m):m_manager(m), m_root(nullptr) {}
 | 
			
		||||
        pred(ast_manager & m):m(m), m_root(0) {}
 | 
			
		||||
 | 
			
		||||
        bool operator()(expr * t) override {
 | 
			
		||||
            TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m_manager) << "\n";);
 | 
			
		||||
            TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m) << "\n";);
 | 
			
		||||
            if (is_app(t)) 
 | 
			
		||||
                return to_app(t)->get_family_id() == m_manager.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
 | 
			
		||||
            return m_manager.is_label(t) || is_quantifier(t);
 | 
			
		||||
                return to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
 | 
			
		||||
            return m.is_label(t) || is_quantifier(t);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,16 +17,16 @@ Notes:
 | 
			
		|||
    Major revision on 2011-10-06
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#include "util/warning.h"
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "ast/normal_forms/nnf.h"
 | 
			
		||||
#include "ast/normal_forms/nnf_params.hpp"
 | 
			
		||||
#include "util/warning.h"
 | 
			
		||||
#include "ast/used_vars.h"
 | 
			
		||||
#include "ast/well_sorted.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
 | 
			
		||||
#include "ast/normal_forms/name_exprs.h"
 | 
			
		||||
#include "ast/act_cache.h"
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/normal_forms/name_exprs.h"
 | 
			
		||||
 | 
			
		||||
#include "ast/ast_smt2_pp.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,36 +67,42 @@ enum nnf_mode {
 | 
			
		|||
class skolemizer {
 | 
			
		||||
    typedef act_cache cache;
 | 
			
		||||
 | 
			
		||||
    ast_manager & m_manager;
 | 
			
		||||
    ast_manager & m;
 | 
			
		||||
    symbol        m_sk_hack;
 | 
			
		||||
    bool          m_sk_hack_enabled;
 | 
			
		||||
    cache         m_cache;
 | 
			
		||||
    cache         m_cache_pr;
 | 
			
		||||
 | 
			
		||||
    void process(quantifier * q, expr_ref & r, proof_ref & p) {
 | 
			
		||||
        if (q->get_kind() == lambda_k) {
 | 
			
		||||
            TRACE("nnf", tout << expr_ref(q, m) << "\n";);
 | 
			
		||||
            r = q;
 | 
			
		||||
            p = nullptr;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        used_vars uv;
 | 
			
		||||
        uv(q);
 | 
			
		||||
        SASSERT(is_well_sorted(m(), q));
 | 
			
		||||
        SASSERT(is_well_sorted(m, q));
 | 
			
		||||
        unsigned sz = uv.get_max_found_var_idx_plus_1();
 | 
			
		||||
        ptr_buffer<sort> sorts;
 | 
			
		||||
        expr_ref_vector args(m());
 | 
			
		||||
        expr_ref_vector args(m);
 | 
			
		||||
        for (unsigned i = 0; i < sz; i++) {
 | 
			
		||||
            sort * s = uv.get(i);
 | 
			
		||||
            if (s != nullptr) {
 | 
			
		||||
                sorts.push_back(s);
 | 
			
		||||
                args.push_back(m().mk_var(i, s));
 | 
			
		||||
                args.push_back(m.mk_var(i, s));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TRACE("skolemizer", tout << "skid: " << q->get_skid() << "\n";);
 | 
			
		||||
        
 | 
			
		||||
        expr_ref_vector substitution(m());
 | 
			
		||||
        expr_ref_vector substitution(m);
 | 
			
		||||
        unsigned num_decls = q->get_num_decls();
 | 
			
		||||
        for (unsigned i = num_decls; i > 0; ) {
 | 
			
		||||
            --i;
 | 
			
		||||
            sort * r            = q->get_decl_sort(i);
 | 
			
		||||
            func_decl * sk_decl = m().mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
 | 
			
		||||
            app * sk            = m().mk_app(sk_decl, args.size(), args.c_ptr());
 | 
			
		||||
            func_decl * sk_decl = m.mk_fresh_func_decl(q->get_decl_name(i), q->get_skid(), sorts.size(), sorts.c_ptr(), r);
 | 
			
		||||
            app * sk            = m.mk_app(sk_decl, args.size(), args.c_ptr());
 | 
			
		||||
            substitution.push_back(sk);
 | 
			
		||||
        }
 | 
			
		||||
        //
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +112,7 @@ class skolemizer {
 | 
			
		|||
        for (unsigned i = 0; i < sz; i++) {
 | 
			
		||||
            sort * s = uv.get(i);
 | 
			
		||||
            if (s != nullptr)
 | 
			
		||||
                substitution.push_back(m().mk_var(i, s));
 | 
			
		||||
                substitution.push_back(m.mk_var(i, s));
 | 
			
		||||
            else
 | 
			
		||||
                substitution.push_back(nullptr);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -118,9 +124,9 @@ class skolemizer {
 | 
			
		|||
        //
 | 
			
		||||
        // (VAR 0) should be in the last position of substitution.
 | 
			
		||||
        //
 | 
			
		||||
        var_subst s(m());
 | 
			
		||||
        SASSERT(is_well_sorted(m(), q->get_expr()));
 | 
			
		||||
        expr_ref tmp(m());
 | 
			
		||||
        var_subst s(m);
 | 
			
		||||
        SASSERT(is_well_sorted(m, q->get_expr()));
 | 
			
		||||
        expr_ref tmp(m);
 | 
			
		||||
        expr * body = q->get_expr();
 | 
			
		||||
        if (m_sk_hack_enabled) {
 | 
			
		||||
            unsigned num_patterns = q->get_num_patterns();
 | 
			
		||||
| 
						 | 
				
			
			@ -128,27 +134,27 @@ class skolemizer {
 | 
			
		|||
                expr * p = q->get_pattern(i);
 | 
			
		||||
                if (is_sk_hack(p)) {
 | 
			
		||||
                    expr * sk_hack = to_app(p)->get_arg(0);
 | 
			
		||||
                    if (q->is_forall()) // check whether is in negative/positive context.
 | 
			
		||||
                        tmp  = m().mk_or(body, m().mk_not(sk_hack)); // negative context
 | 
			
		||||
                    if (q->get_kind() == forall_k) // check whether is in negative/positive context.
 | 
			
		||||
                        tmp  = m.mk_or(body, m.mk_not(sk_hack)); // negative context
 | 
			
		||||
                    else
 | 
			
		||||
                        tmp  = m().mk_and(body, sk_hack); // positive context
 | 
			
		||||
                        tmp  = m.mk_and(body, sk_hack); // positive context
 | 
			
		||||
                    body = tmp;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        s(body, substitution.size(), substitution.c_ptr(), r);
 | 
			
		||||
        r = s(body, substitution.size(), substitution.c_ptr());
 | 
			
		||||
        p = nullptr;
 | 
			
		||||
        if (m().proofs_enabled()) {
 | 
			
		||||
            if (q->is_forall())
 | 
			
		||||
                p = m().mk_skolemization(m().mk_not(q), m().mk_not(r));
 | 
			
		||||
        if (m.proofs_enabled()) {
 | 
			
		||||
            if (q->get_kind() == forall_k) 
 | 
			
		||||
                p = m.mk_skolemization(m.mk_not(q), m.mk_not(r));
 | 
			
		||||
            else
 | 
			
		||||
                p = m().mk_skolemization(q, r);
 | 
			
		||||
                p = m.mk_skolemization(q, r);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    skolemizer(ast_manager & m):
 | 
			
		||||
        m_manager(m),
 | 
			
		||||
        m(m),
 | 
			
		||||
        m_sk_hack("sk_hack"),
 | 
			
		||||
        m_sk_hack_enabled(false),
 | 
			
		||||
        m_cache(m),
 | 
			
		||||
| 
						 | 
				
			
			@ -159,25 +165,23 @@ public:
 | 
			
		|||
        m_sk_hack_enabled  = f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ast_manager & m() const { return m_manager; }
 | 
			
		||||
 | 
			
		||||
    void operator()(quantifier * q, expr_ref & r, proof_ref & p) {
 | 
			
		||||
        r = m_cache.find(q);
 | 
			
		||||
        if (r.get() != nullptr) {
 | 
			
		||||
            p = nullptr;
 | 
			
		||||
            if (m().proofs_enabled())
 | 
			
		||||
            if (m.proofs_enabled())
 | 
			
		||||
                p = static_cast<proof*>(m_cache_pr.find(q));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            process(q, r, p);
 | 
			
		||||
            m_cache.insert(q, r);
 | 
			
		||||
            if (m().proofs_enabled())
 | 
			
		||||
            if (m.proofs_enabled())
 | 
			
		||||
                m_cache_pr.insert(q, p);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_sk_hack(expr * p) const {
 | 
			
		||||
        SASSERT(m().is_pattern(p));
 | 
			
		||||
        SASSERT(m.is_pattern(p));
 | 
			
		||||
        if (to_app(p)->get_num_args() != 1)
 | 
			
		||||
            return false;
 | 
			
		||||
        expr * body = to_app(p)->get_arg(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +190,7 @@ public:
 | 
			
		|||
        func_decl * f = to_app(body)->get_decl();
 | 
			
		||||
        if (!(f->get_name() == m_sk_hack && f->get_arity() == 1))
 | 
			
		||||
            return false;
 | 
			
		||||
        if (!m().is_bool(body)) {
 | 
			
		||||
        if (!m.is_bool(body)) {
 | 
			
		||||
            warning_msg("sk_hack constant must return a Boolean");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +238,7 @@ struct nnf::imp {
 | 
			
		|||
#define NEG_Q_CIDX  2   // negative polarity and nested in a quantifier
 | 
			
		||||
#define POS_Q_CIDX  3   // positive polarity and nested in a quantifier
 | 
			
		||||
    
 | 
			
		||||
    ast_manager &          m_manager;
 | 
			
		||||
    ast_manager &          m;
 | 
			
		||||
    vector<frame>          m_frame_stack;
 | 
			
		||||
    expr_ref_vector        m_result_stack;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -263,7 +267,7 @@ struct nnf::imp {
 | 
			
		|||
    unsigned long long     m_max_memory; // in bytes
 | 
			
		||||
 | 
			
		||||
    imp(ast_manager & m, defined_names & n, params_ref const & p):
 | 
			
		||||
        m_manager(m),
 | 
			
		||||
        m(m),
 | 
			
		||||
        m_result_stack(m),
 | 
			
		||||
        m_todo_defs(m),
 | 
			
		||||
        m_todo_proofs(m),
 | 
			
		||||
| 
						 | 
				
			
			@ -279,9 +283,9 @@ struct nnf::imp {
 | 
			
		|||
        m_name_quant           = mk_quantifier_label_namer(m, n);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ast_manager & m() const { return m_manager; }
 | 
			
		||||
    // ast_manager & m() const { return m; }
 | 
			
		||||
 | 
			
		||||
    bool proofs_enabled() const { return m().proofs_enabled(); }
 | 
			
		||||
    bool proofs_enabled() const { return m.proofs_enabled(); }
 | 
			
		||||
 | 
			
		||||
    ~imp() {
 | 
			
		||||
        for (unsigned i = 0; i < 4; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -334,7 +338,7 @@ struct nnf::imp {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void push_frame(expr * t, bool pol, bool in_q, bool cache_res) {
 | 
			
		||||
        m_frame_stack.push_back(frame(expr_ref(t, m()), pol, in_q, cache_res, m_result_stack.size()));
 | 
			
		||||
        m_frame_stack.push_back(frame(expr_ref(t, m), pol, in_q, cache_res, m_result_stack.size()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static unsigned get_cache_idx(bool pol, bool in_q) {
 | 
			
		||||
| 
						 | 
				
			
			@ -382,8 +386,8 @@ struct nnf::imp {
 | 
			
		|||
        cooperate("nnf");
 | 
			
		||||
        if (memory::get_allocation_size() > m_max_memory)
 | 
			
		||||
            throw nnf_exception(Z3_MAX_MEMORY_MSG);
 | 
			
		||||
        if (m().canceled())
 | 
			
		||||
            throw nnf_exception(m().limit().get_cancel_msg());
 | 
			
		||||
        if (m.canceled()) 
 | 
			
		||||
            throw nnf_exception(m.limit().get_cancel_msg());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_new_child_flag() {
 | 
			
		||||
| 
						 | 
				
			
			@ -397,16 +401,16 @@ struct nnf::imp {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void skip(expr * t, bool pol) {
 | 
			
		||||
        expr * r = pol ? t : m().mk_not(t);
 | 
			
		||||
        expr * r = pol ? t : m.mk_not(t);
 | 
			
		||||
        m_result_stack.push_back(r);
 | 
			
		||||
        if (proofs_enabled()) {
 | 
			
		||||
            m_result_pr_stack.push_back(m().mk_oeq_reflexivity(r));
 | 
			
		||||
            m_result_pr_stack.push_back(m.mk_oeq_reflexivity(r));
 | 
			
		||||
            SASSERT(m_result_stack.size() == m_result_pr_stack.size());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool visit(expr * t, bool pol, bool in_q) {
 | 
			
		||||
        SASSERT(m().is_bool(t));
 | 
			
		||||
        SASSERT(m.is_bool(t));
 | 
			
		||||
 | 
			
		||||
        if (m_mode == NNF_SKOLEM || (m_mode == NNF_QUANT && !in_q)) {
 | 
			
		||||
            if (!has_quantifiers(t) && !has_labels(t)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -456,12 +460,12 @@ struct nnf::imp {
 | 
			
		|||
    proof * mk_proof(bool pol, unsigned num_parents, proof * const * parents, app * old_e, app * new_e) {
 | 
			
		||||
        if (pol) {
 | 
			
		||||
            if (old_e->get_decl() == new_e->get_decl())
 | 
			
		||||
                return m().mk_oeq_congruence(old_e, new_e, num_parents, parents);
 | 
			
		||||
                return m.mk_oeq_congruence(old_e, new_e, num_parents, parents);
 | 
			
		||||
            else 
 | 
			
		||||
                return m().mk_nnf_pos(old_e, new_e, num_parents, parents);
 | 
			
		||||
                return m.mk_nnf_pos(old_e, new_e, num_parents, parents);
 | 
			
		||||
        }
 | 
			
		||||
        else 
 | 
			
		||||
            return m().mk_nnf_neg(old_e, new_e, num_parents, parents);
 | 
			
		||||
            return m.mk_nnf_neg(old_e, new_e, num_parents, parents);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool process_and_or(app * t, frame & fr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -473,10 +477,10 @@ struct nnf::imp {
 | 
			
		|||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        app * r;
 | 
			
		||||
        if (m().is_and(t) == fr.m_pol)
 | 
			
		||||
            r = m().mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
        if (m.is_and(t) == fr.m_pol)
 | 
			
		||||
            r = m.mk_and(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
        else
 | 
			
		||||
            r = m().mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
            r = m.mk_or(t->get_num_args(), m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
        
 | 
			
		||||
        m_result_stack.shrink(fr.m_spos);
 | 
			
		||||
        m_result_stack.push_back(r);
 | 
			
		||||
| 
						 | 
				
			
			@ -500,7 +504,7 @@ struct nnf::imp {
 | 
			
		|||
        if (proofs_enabled()) {
 | 
			
		||||
            pr = m_result_pr_stack.back();
 | 
			
		||||
            if (!fr.m_pol) {
 | 
			
		||||
                pr = m().mk_nnf_neg(t, r, 1, &pr);
 | 
			
		||||
                pr = m.mk_nnf_neg(t, r, 1, &pr);
 | 
			
		||||
                m_result_pr_stack.pop_back();
 | 
			
		||||
                m_result_pr_stack.push_back(pr);
 | 
			
		||||
                SASSERT(m_result_stack.size() == m_result_pr_stack.size());
 | 
			
		||||
| 
						 | 
				
			
			@ -526,9 +530,9 @@ struct nnf::imp {
 | 
			
		|||
 | 
			
		||||
        app * r;
 | 
			
		||||
        if (fr.m_pol)
 | 
			
		||||
            r = m().mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
            r = m.mk_or(2, m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
        else
 | 
			
		||||
            r = m().mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
            r = m.mk_and(2, m_result_stack.c_ptr() + fr.m_spos);
 | 
			
		||||
        
 | 
			
		||||
        m_result_stack.shrink(fr.m_spos);
 | 
			
		||||
        m_result_stack.push_back(r);
 | 
			
		||||
| 
						 | 
				
			
			@ -570,7 +574,7 @@ struct nnf::imp {
 | 
			
		|||
        expr * _then      = rs[2];
 | 
			
		||||
        expr * _else      = rs[3];
 | 
			
		||||
 | 
			
		||||
        app * r = m().mk_and(m().mk_or(_not_cond, _then), m().mk_or(_cond, _else));
 | 
			
		||||
        app * r = m.mk_and(m.mk_or(_not_cond, _then), m.mk_or(_cond, _else));
 | 
			
		||||
        m_result_stack.shrink(fr.m_spos);
 | 
			
		||||
        m_result_stack.push_back(r);
 | 
			
		||||
        if (proofs_enabled()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -582,7 +586,7 @@ struct nnf::imp {
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_eq(app * t) const { return m().is_eq(t); }
 | 
			
		||||
    bool is_eq(app * t) const { return m.is_eq(t); }
 | 
			
		||||
 | 
			
		||||
    bool process_iff_xor(app * t, frame & fr) {
 | 
			
		||||
        SASSERT(t->get_num_args() == 2);
 | 
			
		||||
| 
						 | 
				
			
			@ -615,9 +619,9 @@ struct nnf::imp {
 | 
			
		|||
 | 
			
		||||
        app * r;
 | 
			
		||||
        if (is_eq(t) == fr.m_pol) 
 | 
			
		||||
            r = m().mk_and(m().mk_or(not_lhs, rhs), m().mk_or(lhs, not_rhs));
 | 
			
		||||
            r = m.mk_and(m.mk_or(not_lhs, rhs), m.mk_or(lhs, not_rhs));
 | 
			
		||||
        else
 | 
			
		||||
            r = m().mk_and(m().mk_or(lhs, rhs), m().mk_or(not_lhs, not_rhs));
 | 
			
		||||
            r = m.mk_and(m.mk_or(lhs, rhs), m.mk_or(not_lhs, not_rhs));
 | 
			
		||||
        m_result_stack.shrink(fr.m_spos);
 | 
			
		||||
        m_result_stack.push_back(r);
 | 
			
		||||
        if (proofs_enabled()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -630,7 +634,7 @@ struct nnf::imp {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool process_eq(app * t, frame & fr) {
 | 
			
		||||
        if (m().is_iff(t))
 | 
			
		||||
        if (m.is_bool(t->get_arg(0)))
 | 
			
		||||
            return process_iff_xor(t, fr);
 | 
			
		||||
        else
 | 
			
		||||
            return process_default(t, fr);
 | 
			
		||||
| 
						 | 
				
			
			@ -639,21 +643,20 @@ struct nnf::imp {
 | 
			
		|||
    bool process_default(app * t, frame & fr) {
 | 
			
		||||
        SASSERT(fr.m_i == 0);
 | 
			
		||||
        if (m_mode == NNF_FULL || t->has_quantifiers() || t->has_labels()) {
 | 
			
		||||
            expr_ref  n2(m());
 | 
			
		||||
            proof_ref pr2(m());
 | 
			
		||||
            expr_ref  n2(m);
 | 
			
		||||
            proof_ref pr2(m);
 | 
			
		||||
            if (m_mode == NNF_FULL || (m_mode != NNF_SKOLEM && fr.m_in_q))
 | 
			
		||||
                m_name_nested_formulas->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
 | 
			
		||||
            else
 | 
			
		||||
                m_name_quant->operator()(t, m_todo_defs, m_todo_proofs, n2, pr2);
 | 
			
		||||
 | 
			
		||||
            if (!fr.m_pol)
 | 
			
		||||
                n2 = m().mk_not(n2);
 | 
			
		||||
 | 
			
		||||
                n2 = m.mk_not(n2);
 | 
			
		||||
            m_result_stack.push_back(n2);
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                if (!fr.m_pol) {
 | 
			
		||||
                    proof * prs[1] = { pr2 };
 | 
			
		||||
                     pr2 = m().mk_oeq_congruence(m().mk_not(t), static_cast<app*>(n2.get()), 1, prs);
 | 
			
		||||
                    pr2 = m.mk_oeq_congruence(m.mk_not(t), static_cast<app*>(n2.get()), 1, prs);
 | 
			
		||||
                }
 | 
			
		||||
                m_result_pr_stack.push_back(pr2);
 | 
			
		||||
                SASSERT(m_result_stack.size() == m_result_pr_stack.size());
 | 
			
		||||
| 
						 | 
				
			
			@ -681,24 +684,24 @@ struct nnf::imp {
 | 
			
		|||
 | 
			
		||||
        buffer<symbol> names;
 | 
			
		||||
        bool pos;
 | 
			
		||||
        m().is_label(t, pos, names);
 | 
			
		||||
        expr_ref r(m());
 | 
			
		||||
        proof_ref pr(m());
 | 
			
		||||
        m.is_label(t, pos, names);
 | 
			
		||||
        expr_ref r(m);
 | 
			
		||||
        proof_ref pr(m);
 | 
			
		||||
        if (fr.m_pol == pos) {
 | 
			
		||||
            expr * lbl_lit = m().mk_label_lit(names.size(), names.c_ptr());
 | 
			
		||||
            r              = m().mk_and(arg, lbl_lit);
 | 
			
		||||
            expr * lbl_lit = m.mk_label_lit(names.size(), names.c_ptr());
 | 
			
		||||
            r              = m.mk_and(arg, lbl_lit);
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                expr_ref aux(m_manager);
 | 
			
		||||
                aux = m().mk_label(true, names.size(), names.c_ptr(), arg);
 | 
			
		||||
                pr = m().mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
 | 
			
		||||
                                         m().mk_iff_oeq(m().mk_rewrite(aux, r)));
 | 
			
		||||
                expr_ref aux(m);
 | 
			
		||||
                aux = m.mk_label(true, names.size(), names.c_ptr(), arg);
 | 
			
		||||
                pr = m.mk_transitivity(mk_proof(fr.m_pol, 1, &arg_pr, t, to_app(aux)),
 | 
			
		||||
                                         m.mk_iff_oeq(m.mk_rewrite(aux, r)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            r = arg;
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                proof * p1 = m().mk_iff_oeq(m().mk_rewrite(t, t->get_arg(0)));
 | 
			
		||||
                pr = m().mk_transitivity(p1, arg_pr);
 | 
			
		||||
                proof * p1 = m.mk_iff_oeq(m.mk_rewrite(t, t->get_arg(0)));
 | 
			
		||||
                pr = m.mk_transitivity(p1, arg_pr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -713,9 +716,9 @@ struct nnf::imp {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool process_app(app * t, frame & fr) {
 | 
			
		||||
        TRACE("nnf", tout << mk_ismt2_pp(t, m()) << "\n";);
 | 
			
		||||
        SASSERT(m().is_bool(t));
 | 
			
		||||
        if (t->get_family_id() == m().get_basic_family_id()) {
 | 
			
		||||
        TRACE("nnf", tout << mk_ismt2_pp(t, m) << "\n";);
 | 
			
		||||
        SASSERT(m.is_bool(t));
 | 
			
		||||
        if (t->get_family_id() == m.get_basic_family_id()) {
 | 
			
		||||
            switch (static_cast<basic_op_kind>(t->get_decl_kind())) {
 | 
			
		||||
            case OP_AND: case OP_OR:
 | 
			
		||||
                return process_and_or(t, fr);
 | 
			
		||||
| 
						 | 
				
			
			@ -734,7 +737,7 @@ struct nnf::imp {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (m().is_label(t)) {
 | 
			
		||||
        if (m.is_label(t)) {
 | 
			
		||||
            return process_label(t, fr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -747,28 +750,51 @@ struct nnf::imp {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool process_quantifier(quantifier * q, frame & fr) {
 | 
			
		||||
        expr_ref  r(m());
 | 
			
		||||
        proof_ref pr(m());
 | 
			
		||||
        TRACE("nnf", tout << expr_ref(q, m) << "\n";);
 | 
			
		||||
        expr_ref  r(m);
 | 
			
		||||
        proof_ref pr(m);
 | 
			
		||||
        if (fr.m_i == 0) {
 | 
			
		||||
            fr.m_i = 1;
 | 
			
		||||
            if (q->is_forall() == fr.m_pol || !m_skolemize) {
 | 
			
		||||
            if (is_lambda(q)) {
 | 
			
		||||
                if (!visit(q->get_expr(), fr.m_pol, true))
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
            else if (is_forall(q) == fr.m_pol || !m_skolemize) {
 | 
			
		||||
                if (!visit(q->get_expr(), fr.m_pol, true))
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                m_skolemizer(q, r, pr);
 | 
			
		||||
                if (!visit(r, !q->is_forall(), fr.m_in_q))
 | 
			
		||||
                if (!visit(r, !is_forall(q), fr.m_in_q))
 | 
			
		||||
                    return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (q->is_forall() == fr.m_pol || !m_skolemize) {
 | 
			
		||||
        if (is_lambda(q)) {
 | 
			
		||||
            expr * new_expr = m_result_stack.back();
 | 
			
		||||
            quantifier * new_q = m.update_quantifier(q, new_expr);
 | 
			
		||||
            proof * new_q_pr   = nullptr;
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                // proof * new_expr_pr = m_result_pr_stack.back();
 | 
			
		||||
                new_q_pr = m.mk_rewrite(q, new_q);  // TBD use new_expr_pr
 | 
			
		||||
            }
 | 
			
		||||
                                                      
 | 
			
		||||
            m_result_stack.pop_back();
 | 
			
		||||
            m_result_stack.push_back(new_q);
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                m_result_pr_stack.pop_back();
 | 
			
		||||
                m_result_pr_stack.push_back(new_q_pr);
 | 
			
		||||
                SASSERT(m_result_stack.size() == m_result_pr_stack.size());
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        else if (is_forall(q) == fr.m_pol || !m_skolemize) {
 | 
			
		||||
            expr * new_expr     = m_result_stack.back();
 | 
			
		||||
            proof * new_expr_pr = proofs_enabled() ? m_result_pr_stack.back() : nullptr;
 | 
			
		||||
 | 
			
		||||
            ptr_buffer<expr> new_patterns;
 | 
			
		||||
 | 
			
		||||
            if (q->is_forall() == fr.m_pol) {
 | 
			
		||||
            if (is_forall(q) == fr.m_pol) {
 | 
			
		||||
                // collect non sk_hack patterns
 | 
			
		||||
                unsigned num_patterns = q->get_num_patterns();
 | 
			
		||||
                for (unsigned i = 0; i < num_patterns; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -785,14 +811,19 @@ struct nnf::imp {
 | 
			
		|||
            quantifier * new_q = nullptr;
 | 
			
		||||
            proof * new_q_pr   = nullptr;
 | 
			
		||||
            if (fr.m_pol) {
 | 
			
		||||
                new_q = m().update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
 | 
			
		||||
                if (proofs_enabled())
 | 
			
		||||
                    new_q_pr = m().mk_nnf_pos(q, new_q, 1, &new_expr_pr);
 | 
			
		||||
                new_q = m.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(), new_expr);
 | 
			
		||||
                if (proofs_enabled()) {
 | 
			
		||||
                    new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
 | 
			
		||||
                    new_q_pr = m.mk_nnf_pos(q, new_q, 1, &new_expr_pr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                new_q = m().update_quantifier(q, !q->is_forall(), new_patterns.size(), new_patterns.c_ptr(), new_expr);
 | 
			
		||||
                if (proofs_enabled())
 | 
			
		||||
                    new_q_pr = m().mk_nnf_neg(q, new_q, 1, &new_expr_pr);
 | 
			
		||||
                quantifier_kind k = is_forall(q)? exists_k : forall_k;
 | 
			
		||||
                new_q = m.update_quantifier(q, k, new_patterns.size(), new_patterns.c_ptr(), new_expr);
 | 
			
		||||
                if (proofs_enabled()) {
 | 
			
		||||
                    new_expr_pr = m.mk_bind_proof(q, new_expr_pr);
 | 
			
		||||
                    new_q_pr = m.mk_nnf_neg(q, new_q, 1, &new_expr_pr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            m_result_stack.pop_back();
 | 
			
		||||
| 
						 | 
				
			
			@ -809,7 +840,7 @@ struct nnf::imp {
 | 
			
		|||
            // However, the proof must be updated
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                m_skolemizer(q, r, pr); // retrieve the proof
 | 
			
		||||
                pr = m().mk_transitivity(pr, m_result_pr_stack.back());
 | 
			
		||||
                pr = m.mk_transitivity(pr, m_result_pr_stack.back());
 | 
			
		||||
                m_result_pr_stack.pop_back();
 | 
			
		||||
                m_result_pr_stack.push_back(pr);
 | 
			
		||||
                SASSERT(m_result_stack.size() == m_result_pr_stack.size());
 | 
			
		||||
| 
						 | 
				
			
			@ -827,14 +858,14 @@ struct nnf::imp {
 | 
			
		|||
            result_pr = m_result_pr_stack.back();
 | 
			
		||||
            m_result_pr_stack.pop_back();
 | 
			
		||||
            if (result_pr.get() == nullptr)
 | 
			
		||||
                result_pr = m().mk_reflexivity(t);
 | 
			
		||||
                result_pr = m.mk_reflexivity(t);
 | 
			
		||||
            SASSERT(m_result_pr_stack.empty());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void process(expr * t, expr_ref & result, proof_ref & result_pr) {
 | 
			
		||||
        TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m()) << "\n";);
 | 
			
		||||
        SASSERT(m().is_bool(t));
 | 
			
		||||
        TRACE("nnf", tout << "processing:\n" << mk_ismt2_pp(t, m) << "\n";);
 | 
			
		||||
        SASSERT(m.is_bool(t));
 | 
			
		||||
 | 
			
		||||
        if (visit(t, true /* positive polarity */, false /* not nested in quantifier */)) {
 | 
			
		||||
            recover_result(t, result, result_pr);
 | 
			
		||||
| 
						 | 
				
			
			@ -883,12 +914,12 @@ struct nnf::imp {
 | 
			
		|||
        unsigned old_sz2 = new_def_proofs.size();
 | 
			
		||||
 | 
			
		||||
        for (unsigned i = 0; i < m_todo_defs.size(); i++) {
 | 
			
		||||
            expr_ref  dr(m());
 | 
			
		||||
            proof_ref dpr(m());
 | 
			
		||||
            expr_ref  dr(m);
 | 
			
		||||
            proof_ref dpr(m);
 | 
			
		||||
            process(m_todo_defs.get(i), dr, dpr);
 | 
			
		||||
            new_defs.push_back(dr);
 | 
			
		||||
            if (proofs_enabled()) {
 | 
			
		||||
                proof * new_pr = m().mk_modus_ponens(m_todo_proofs.get(i), dpr);
 | 
			
		||||
                proof * new_pr = m.mk_modus_ponens(m_todo_proofs.get(i), dpr);
 | 
			
		||||
                new_def_proofs.push_back(new_pr); 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -909,7 +940,7 @@ nnf::~nnf() {
 | 
			
		|||
 | 
			
		||||
void nnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r,  proof_ref & p) {
 | 
			
		||||
    m_imp->operator()(n, new_defs, new_def_proofs, r, p);
 | 
			
		||||
    TRACE("nnf_result", tout << mk_ismt2_pp(n, m_imp->m()) << "\nNNF result:\n" << mk_ismt2_pp(r, m_imp->m()) << "\n";);
 | 
			
		||||
    TRACE("nnf_result", tout << expr_ref(n, r.get_manager()) << "\nNNF result:\n" << new_defs << "\n" << r << "\n";);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nnf::updt_params(params_ref const & p) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,8 @@ struct pull_quant::imp {
 | 
			
		|||
                if (is_quantifier(child)) {
 | 
			
		||||
                    quantifier * q = to_quantifier(child);
 | 
			
		||||
                    expr * body = q->get_expr();
 | 
			
		||||
                    result = m_manager.update_quantifier(q, !q->is_forall(), m_manager.mk_not(body));
 | 
			
		||||
                    quantifier_kind k = q->get_kind() == forall_k ? exists_k : forall_k;
 | 
			
		||||
                    result = m_manager.update_quantifier(q, k, m_manager.mk_not(body));
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +150,7 @@ struct pull_quant::imp {
 | 
			
		|||
                // 3) MBQI 
 | 
			
		||||
                std::reverse(var_sorts.begin(), var_sorts.end());
 | 
			
		||||
                std::reverse(var_names.begin(), var_names.end());
 | 
			
		||||
                result = m_manager.mk_quantifier(forall_children,
 | 
			
		||||
                result = m_manager.mk_quantifier(forall_children ? forall_k : exists_k,
 | 
			
		||||
                                                 var_sorts.size(),
 | 
			
		||||
                                                 var_sorts.c_ptr(),
 | 
			
		||||
                                                 var_names.c_ptr(),
 | 
			
		||||
| 
						 | 
				
			
			@ -220,9 +221,7 @@ struct pull_quant::imp {
 | 
			
		|||
                expr_ref_buffer   new_args(m_manager);
 | 
			
		||||
                expr_ref          new_arg(m_manager);
 | 
			
		||||
                ptr_buffer<proof> proofs;
 | 
			
		||||
                unsigned num = to_app(n)->get_num_args();
 | 
			
		||||
                for (unsigned i = 0; i < num; i++) {
 | 
			
		||||
                    expr * arg = to_app(n)->get_arg(i); 
 | 
			
		||||
                for (expr * arg : *to_app(n)) {
 | 
			
		||||
                    pull_quant1(arg , new_arg);
 | 
			
		||||
                    new_args.push_back(new_arg);
 | 
			
		||||
                    if (new_arg != arg)
 | 
			
		||||
| 
						 | 
				
			
			@ -277,10 +276,13 @@ struct pull_quant::imp {
 | 
			
		|||
                               expr_ref & result,
 | 
			
		||||
                               proof_ref & result_pr) {
 | 
			
		||||
 | 
			
		||||
            if (old_q->is_exists()) {
 | 
			
		||||
            if (is_exists(old_q)) {
 | 
			
		||||
                UNREACHABLE();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            if (is_lambda(old_q)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!is_forall(new_body))
 | 
			
		||||
                return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ expr_pattern_match::match_quantifier(quantifier* qf, app_ref_vector& patterns, u
 | 
			
		|||
    m_regs[0] = qf->get_expr();
 | 
			
		||||
    for (unsigned i = 0; i < m_precompiled.size(); ++i) {
 | 
			
		||||
        quantifier* qf2 = m_precompiled[i].get();
 | 
			
		||||
        if (qf2->is_forall() != qf->is_forall()) {
 | 
			
		||||
        if (qf2->get_kind() != qf->get_kind() || is_lambda(qf)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (qf2->get_num_decls() != qf->get_num_decls()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -582,7 +582,7 @@ bool pattern_inference_cfg::reduce_quantifier(
 | 
			
		|||
    proof_ref & result_pr) {
 | 
			
		||||
 | 
			
		||||
    TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
 | 
			
		||||
    if (!q->is_forall()) {
 | 
			
		||||
    if (!is_forall(q)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -673,6 +673,7 @@ bool pattern_inference_cfg::reduce_quantifier(
 | 
			
		|||
        new_q = m.update_quantifier_weight(new_q, weight);
 | 
			
		||||
    if (m.proofs_enabled()) {
 | 
			
		||||
        proof* new_body_pr = m.mk_reflexivity(new_body);
 | 
			
		||||
        new_body_pr = m.mk_bind_proof(new_q, new_body_pr);
 | 
			
		||||
        result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -690,7 +691,7 @@ bool pattern_inference_cfg::reduce_quantifier(
 | 
			
		|||
                }
 | 
			
		||||
                new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
 | 
			
		||||
                if (m.proofs_enabled()) {
 | 
			
		||||
                    result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
 | 
			
		||||
                    result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_bind_proof(new_q, m.mk_reflexivity(new_q->get_expr()))));
 | 
			
		||||
                }
 | 
			
		||||
                TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -346,7 +346,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
 | 
			
		|||
            to_quantifier(t1.get())->get_expr() == s1.get() &&
 | 
			
		||||
            to_quantifier(t2.get())->get_expr() == s2.get() &&
 | 
			
		||||
            to_quantifier(t1.get())->get_num_decls() == to_quantifier(t2.get())->get_num_decls() &&
 | 
			
		||||
            to_quantifier(t1.get())->is_forall() == to_quantifier(t2.get())->is_forall()) {
 | 
			
		||||
            to_quantifier(t1.get())->get_kind() == to_quantifier(t2.get())->get_kind()) {
 | 
			
		||||
            quantifier* q1 = to_quantifier(t1.get());
 | 
			
		||||
            quantifier* q2 = to_quantifier(t2.get());
 | 
			
		||||
            for (unsigned i = 0; i < q1->get_num_decls(); ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -734,9 +734,10 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
 | 
			
		|||
                is_forall = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (is_quantifier(e)) {
 | 
			
		||||
                SASSERT(!is_lambda(e));
 | 
			
		||||
                q = to_quantifier(e);                
 | 
			
		||||
                // TBD check that quantifier is properly instantiated
 | 
			
		||||
                return is_forall == q->is_forall();
 | 
			
		||||
                return is_forall == ::is_forall(q);                
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
| 
						 | 
				
			
			@ -784,7 +785,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) {
 | 
			
		|||
                    // SASSERT(to_quantifier(premise)->get_num_decls() == sub.size());
 | 
			
		||||
                    premise = to_quantifier(premise)->get_expr();
 | 
			
		||||
                }
 | 
			
		||||
                vs(premise, sub.size(), sub.c_ptr(), premise);
 | 
			
		||||
                premise = vs(premise, sub.size(), sub.c_ptr());
 | 
			
		||||
            }
 | 
			
		||||
            fmls.push_back(premise.get());
 | 
			
		||||
            TRACE("proof_checker",
 | 
			
		||||
| 
						 | 
				
			
			@ -974,7 +975,7 @@ bool proof_checker::match_app(expr const* e, func_decl_ref& d, expr_ref_vector&
 | 
			
		|||
bool proof_checker::match_quantifier(expr const* e, bool& is_univ, sort_ref_vector& sorts, expr_ref& body) const {
 | 
			
		||||
    if (is_quantifier(e)) {
 | 
			
		||||
        quantifier const* q = to_quantifier(e);
 | 
			
		||||
        is_univ = q->is_forall();
 | 
			
		||||
        is_univ = is_forall(q);
 | 
			
		||||
        body = q->get_expr();
 | 
			
		||||
        for (unsigned i = 0; i < q->get_num_decls(); ++i) {
 | 
			
		||||
            sorts.push_back(q->get_decl_sort(i));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -975,9 +975,7 @@ private:
 | 
			
		|||
 | 
			
		||||
    void compose(expr_ref_vector& sub, expr_ref_vector const& s0) {
 | 
			
		||||
        for (unsigned i = 0; i < sub.size(); ++i) {
 | 
			
		||||
            expr_ref e(m);
 | 
			
		||||
            var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr(), e);
 | 
			
		||||
            sub[i] = e;            
 | 
			
		||||
            sub[i] = var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -995,7 +993,7 @@ private:
 | 
			
		|||
                  tout << sub.size() << "\n";);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml);
 | 
			
		||||
        fml = var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ Notes:
 | 
			
		|||
#include "ast/rewriter/array_rewriter_params.hpp"
 | 
			
		||||
#include "ast/ast_lt.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
 | 
			
		||||
void array_rewriter::updt_params(params_ref const & _p) {
 | 
			
		||||
    array_rewriter_params p(_p);
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +197,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
 | 
			
		|||
        return BR_DONE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (is_lambda(args[0])) {
 | 
			
		||||
        // anywhere lambda reduction as opposed to whnf
 | 
			
		||||
        // select(lambda(X) M, N) -> M[N/X]
 | 
			
		||||
        quantifier* q = to_quantifier(args[0]);
 | 
			
		||||
        SASSERT(q->get_num_decls() == num_args - 1);
 | 
			
		||||
        var_subst subst(m());
 | 
			
		||||
        result = subst(q->get_expr(), num_args - 1, args + 1);
 | 
			
		||||
        return BR_REWRITE_FULL;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (m_util.is_as_array(args[0])) {
 | 
			
		||||
        // select(as-array[f], I) --> f(I)
 | 
			
		||||
        func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -636,7 +636,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend);
 | 
			
		|||
                new_decl_names.push_back(n);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
 | 
			
		||||
        result = m().mk_quantifier(old_q->get_kind(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
 | 
			
		||||
                                   new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
 | 
			
		||||
                                   old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
 | 
			
		||||
        result_pr = nullptr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -588,58 +588,39 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
 | 
			
		|||
    VERIFY(m().is_ite(ite, cond, t, e));
 | 
			
		||||
    SASSERT(m().is_value(val));
 | 
			
		||||
 | 
			
		||||
    if (m().is_value(t) && m().is_value(e)) {
 | 
			
		||||
        if (t != val && e != val) {
 | 
			
		||||
            TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
 | 
			
		||||
                  tout << t << " " << e << " " << val << "\n";);
 | 
			
		||||
            result = m().mk_false();
 | 
			
		||||
        }
 | 
			
		||||
        else if (t == val && e == val) {
 | 
			
		||||
    if (m().are_distinct(val, e)) {
 | 
			
		||||
        result = m().mk_and(m().mk_eq(t, val), cond);
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
    if (m().are_distinct(val, t)) {
 | 
			
		||||
        result = m().mk_and(m().mk_eq(e, val), m().mk_not(cond));
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
    if (m().are_equal(val, t)) {
 | 
			
		||||
        if (m().are_equal(val, e)) {
 | 
			
		||||
            result = m().mk_true();
 | 
			
		||||
        }
 | 
			
		||||
        else if (t == val) {
 | 
			
		||||
            result = cond;
 | 
			
		||||
            return BR_DONE;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            SASSERT(e == val);
 | 
			
		||||
            mk_not(cond, result);
 | 
			
		||||
            result = m().mk_or(m().mk_eq(e, val), cond);
 | 
			
		||||
        }
 | 
			
		||||
        return BR_DONE;
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
    if (m_ite_extra_rules) {
 | 
			
		||||
        if (m().is_value(t)) {
 | 
			
		||||
            if (val == t) {
 | 
			
		||||
                result = m().mk_or(cond, m().mk_eq(val, e));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                mk_not(cond, result);
 | 
			
		||||
                result = m().mk_and(result, m().mk_eq(val, e));
 | 
			
		||||
            }
 | 
			
		||||
            return BR_REWRITE2;
 | 
			
		||||
        }
 | 
			
		||||
        if (m().is_value(e)) {
 | 
			
		||||
            if (val == e) {
 | 
			
		||||
                mk_not(cond, result);
 | 
			
		||||
                result = m().mk_or(result, m().mk_eq(val, t));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                result = m().mk_and(cond, m().mk_eq(val, t));
 | 
			
		||||
            }
 | 
			
		||||
            return BR_REWRITE2;
 | 
			
		||||
        }
 | 
			
		||||
    if (m().are_equal(val, e)) {
 | 
			
		||||
        result = m().mk_or(m().mk_eq(t, val), m().mk_not(cond));
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        expr* cond2, *t2, *e2;
 | 
			
		||||
        if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
 | 
			
		||||
            try_ite_value(to_app(t), val, result);
 | 
			
		||||
            result = m().mk_ite(cond, result, m().mk_eq(e, val));
 | 
			
		||||
            return BR_REWRITE2;
 | 
			
		||||
        }
 | 
			
		||||
        if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
 | 
			
		||||
            try_ite_value(to_app(e), val, result);
 | 
			
		||||
            result = m().mk_ite(cond, m().mk_eq(t, val), result);
 | 
			
		||||
            return BR_REWRITE2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    expr* cond2 = nullptr, *t2 = nullptr, *e2 = nullptr;
 | 
			
		||||
    if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
 | 
			
		||||
        try_ite_value(to_app(t), val, result);
 | 
			
		||||
        result = m().mk_ite(cond, result, m().mk_eq(e, val));
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
    if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
 | 
			
		||||
        try_ite_value(to_app(e), val, result);
 | 
			
		||||
        result = m().mk_ite(cond, m().mk_eq(t, val), result);
 | 
			
		||||
        return BR_REWRITE2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return BR_FAILED;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,20 +87,16 @@ bool bv_elim_cfg::reduce_quantifier(quantifier * q,
 | 
			
		|||
    expr* const* sub  = subst_map.c_ptr();
 | 
			
		||||
    unsigned sub_size = subst_map.size();
 | 
			
		||||
 | 
			
		||||
    subst(old_body, sub_size, sub, new_body);
 | 
			
		||||
    new_body = subst(old_body, sub_size, sub);
 | 
			
		||||
 | 
			
		||||
    for (unsigned j = 0; j < q->get_num_patterns(); j++) {
 | 
			
		||||
        expr_ref pat(m);        
 | 
			
		||||
        subst(new_patterns[j], sub_size, sub, pat);
 | 
			
		||||
        pats.push_back(pat);
 | 
			
		||||
        pats.push_back(subst(new_patterns[j], sub_size, sub));
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
 | 
			
		||||
        expr_ref nopat(m);
 | 
			
		||||
        subst(new_no_patterns[j], sub_size, sub, nopat);
 | 
			
		||||
        no_pats.push_back(nopat);
 | 
			
		||||
        no_pats.push_back(subst(new_no_patterns[j], sub_size, sub));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = m.mk_quantifier(true, 
 | 
			
		||||
    result = m.mk_quantifier(forall_k, 
 | 
			
		||||
                        names.size(),
 | 
			
		||||
                        sorts.c_ptr(),
 | 
			
		||||
                        names.c_ptr(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,7 +133,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
 | 
			
		|||
    // Eliminate variables that have become unused
 | 
			
		||||
    if (reduced && is_forall(r)) {
 | 
			
		||||
        quantifier * q = to_quantifier(r);
 | 
			
		||||
        elim_unused_vars(m_manager, q, params_ref(), r);
 | 
			
		||||
        r = elim_unused_vars(m_manager, q, params_ref());
 | 
			
		||||
        if (m_manager.proofs_enabled()) {
 | 
			
		||||
            proof * p1 = m_manager.mk_elim_unused_vars(q, r);
 | 
			
		||||
            pr = m_manager.mk_transitivity(pr, p1);
 | 
			
		||||
| 
						 | 
				
			
			@ -343,8 +343,7 @@ void der::create_substitution(unsigned sz) {
 | 
			
		|||
        expr_ref cur(m_map[m_order[i]], m_manager);
 | 
			
		||||
 | 
			
		||||
        // do all the previous substitutions before inserting
 | 
			
		||||
        expr_ref r(m_manager);
 | 
			
		||||
        m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
 | 
			
		||||
        expr_ref r = m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
 | 
			
		||||
        unsigned inx = sz - m_order[i]- 1;
 | 
			
		||||
        SASSERT(m_subst_map[inx]==0);
 | 
			
		||||
| 
						 | 
				
			
			@ -369,21 +368,18 @@ void der::apply_substitution(quantifier * q, expr_ref & r) {
 | 
			
		|||
    unsigned sz = m_new_args.size();
 | 
			
		||||
    expr_ref t(m_manager);
 | 
			
		||||
    t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
 | 
			
		||||
    expr_ref new_e(m_manager);
 | 
			
		||||
    m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
 | 
			
		||||
    expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
 | 
			
		||||
    // don't forget to update the quantifier patterns
 | 
			
		||||
    expr_ref_buffer  new_patterns(m_manager);
 | 
			
		||||
    expr_ref_buffer  new_no_patterns(m_manager);
 | 
			
		||||
    for (unsigned j = 0; j < q->get_num_patterns(); j++) {
 | 
			
		||||
        expr_ref new_pat(m_manager);
 | 
			
		||||
        m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
 | 
			
		||||
        expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
        new_patterns.push_back(new_pat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
 | 
			
		||||
        expr_ref new_nopat(m_manager);
 | 
			
		||||
        m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
 | 
			
		||||
        expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
        new_no_patterns.push_back(new_nopat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ void distribute_forall::reduce1_app(app * a) {
 | 
			
		|||
 | 
			
		||||
void distribute_forall::reduce1_quantifier(quantifier * q) {
 | 
			
		||||
    // This transformation is applied after skolemization/quantifier elimination. So, all quantifiers are universal.
 | 
			
		||||
    SASSERT(q->is_forall());
 | 
			
		||||
    SASSERT(q->get_kind() == forall_k);
 | 
			
		||||
 | 
			
		||||
    // This transformation is applied after basic pre-processing steps.
 | 
			
		||||
    // So, we can assume that
 | 
			
		||||
| 
						 | 
				
			
			@ -126,8 +126,7 @@ void distribute_forall::reduce1_quantifier(quantifier * q) {
 | 
			
		|||
            br.mk_not(arg, not_arg);
 | 
			
		||||
            quantifier_ref tmp_q(m_manager);
 | 
			
		||||
            tmp_q = m_manager.update_quantifier(q, not_arg);
 | 
			
		||||
            expr_ref new_q(m_manager);
 | 
			
		||||
            elim_unused_vars(m_manager, tmp_q, params_ref(), new_q);
 | 
			
		||||
            expr_ref new_q = elim_unused_vars(m_manager, tmp_q, params_ref());
 | 
			
		||||
            new_args.push_back(new_q);
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref result(m_manager);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
 | 
			
		|||
                                     expr * const * new_no_patterns,
 | 
			
		||||
                                     expr_ref & result,
 | 
			
		||||
                                     proof_ref & result_pr) {
 | 
			
		||||
    if (!q->is_forall()) {
 | 
			
		||||
    if (!is_forall(q)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    unsigned num_vars = q->get_num_decls();
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +194,7 @@ bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
 | 
			
		|||
    }
 | 
			
		||||
    quantifier_ref new_q(m);
 | 
			
		||||
    new_q = m.update_quantifier(q, new_body);
 | 
			
		||||
    elim_unused_vars(m, new_q, params_ref(), result);
 | 
			
		||||
    result = elim_unused_vars(m, new_q, params_ref());
 | 
			
		||||
    result_pr = m.mk_rewrite(q, result);
 | 
			
		||||
    TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,6 +159,8 @@ struct enum2bv_rewriter::imp {
 | 
			
		|||
            expr * const * new_no_patterns,
 | 
			
		||||
            expr_ref & result,
 | 
			
		||||
            proof_ref & result_pr) {
 | 
			
		||||
 | 
			
		||||
            if (q->get_kind() == lambda_k) return false;
 | 
			
		||||
            m_sorts.reset();
 | 
			
		||||
            expr_ref_vector bounds(m);
 | 
			
		||||
            bool found = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,15 +184,20 @@ struct enum2bv_rewriter::imp {
 | 
			
		|||
            }
 | 
			
		||||
            expr_ref new_body_ref(old_body, m), tmp(m);
 | 
			
		||||
            if (!bounds.empty()) {
 | 
			
		||||
                if (q->is_forall()) {
 | 
			
		||||
                switch (q->get_kind()) {
 | 
			
		||||
                case forall_k:
 | 
			
		||||
                    new_body_ref = m.mk_implies(mk_and(bounds), new_body_ref);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    break;
 | 
			
		||||
                case exists_k:
 | 
			
		||||
                    bounds.push_back(new_body_ref);
 | 
			
		||||
                    new_body_ref = mk_and(bounds);
 | 
			
		||||
                    break;
 | 
			
		||||
                case lambda_k:
 | 
			
		||||
                    UNREACHABLE();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            result = m.mk_quantifier(q->is_forall(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref, 
 | 
			
		||||
            result = m.mk_quantifier(q->get_kind(), q->get_num_decls(), m_sorts.c_ptr(), q->get_decl_names(), new_body_ref, 
 | 
			
		||||
                                     q->get_weight(), q->get_qid(), q->get_skid(), 
 | 
			
		||||
                                     q->get_num_patterns(), new_patterns,
 | 
			
		||||
                                     q->get_num_no_patterns(), new_no_patterns);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
 | 
			
		|||
    expr* arg1 = nullptr, * arg2 = nullptr, *narg = nullptr;
 | 
			
		||||
    expr* app1 = nullptr, * app2 = nullptr;
 | 
			
		||||
    expr* var1 = nullptr, * var2 = nullptr;
 | 
			
		||||
    if (q->is_forall() && m.is_or(n, arg1, arg2)) {
 | 
			
		||||
    if (is_forall(q) && m.is_or(n, arg1, arg2)) {
 | 
			
		||||
        if (m.is_not(arg2)) 
 | 
			
		||||
            std::swap(arg1, arg2);
 | 
			
		||||
        if (m.is_not(arg1, narg) && 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -79,12 +79,12 @@ public:
 | 
			
		|||
            vars.push_back(a);
 | 
			
		||||
        }
 | 
			
		||||
        expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd);
 | 
			
		||||
        instantiate(m, q, exprs, result);
 | 
			
		||||
        result = instantiate(m, q, exprs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
 | 
			
		||||
    unsigned pull_quantifier(bool _is_forall, expr_ref& fml, ptr_vector<sort>* sorts, svector<symbol>* names, bool use_fresh, bool rewrite_ok) {
 | 
			
		||||
        unsigned index = var_counter().get_next_var(fml);
 | 
			
		||||
        while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) {
 | 
			
		||||
        while (is_quantifier(fml) && _is_forall == is_forall(fml)) {
 | 
			
		||||
            quantifier* q = to_quantifier(fml);
 | 
			
		||||
            index += q->get_num_decls();
 | 
			
		||||
            if (names) {
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ public:
 | 
			
		|||
            return index;
 | 
			
		||||
        }
 | 
			
		||||
        app_ref_vector vars(m);
 | 
			
		||||
        pull_quantifier(is_forall, fml, vars, use_fresh, rewrite_ok);
 | 
			
		||||
        pull_quantifier(_is_forall, fml, vars, use_fresh, rewrite_ok);
 | 
			
		||||
        if (vars.empty()) {
 | 
			
		||||
            return index;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -277,12 +277,16 @@ private:
 | 
			
		|||
        }
 | 
			
		||||
        case AST_QUANTIFIER: {
 | 
			
		||||
            quantifier* q = to_quantifier(fml);
 | 
			
		||||
            expr_ref tmp(m);
 | 
			
		||||
            if (!is_compatible(qt, q->is_forall())) {
 | 
			
		||||
            if (is_lambda(q)) {
 | 
			
		||||
                result = fml;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            set_quantifier_type(qt, q->is_forall());
 | 
			
		||||
            expr_ref tmp(m);
 | 
			
		||||
            if (!is_compatible(qt, is_forall(q))) {
 | 
			
		||||
                result = fml;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            set_quantifier_type(qt, is_forall(q));
 | 
			
		||||
            extract_quantifier(q, vars, tmp, use_fresh);
 | 
			
		||||
            pull_quantifier(tmp, qt, vars, result, use_fresh, rewrite_ok);
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -208,12 +208,10 @@ void rewriter_core::cleanup() {
 | 
			
		|||
 | 
			
		||||
#ifdef _TRACE
 | 
			
		||||
void rewriter_core::display_stack(std::ostream & out, unsigned pp_depth) {
 | 
			
		||||
    svector<frame>::iterator it  = m_frame_stack.begin();
 | 
			
		||||
    svector<frame>::iterator end = m_frame_stack.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        out << mk_bounded_pp(it->m_curr, m(), pp_depth) << "\n";
 | 
			
		||||
        out << "state: " << it->m_state << "\n";
 | 
			
		||||
        out << "cache: " << it->m_cache_result << ", new_child: " << it->m_new_child << ", max-depth: " << it->m_max_depth << ", i: " << it->m_i << "\n";
 | 
			
		||||
    for (frame& f : m_frame_stack) {
 | 
			
		||||
        out << mk_bounded_pp(f.m_curr, m(), pp_depth) << "\n";
 | 
			
		||||
        out << "state: " << f.m_state << "\n";
 | 
			
		||||
        out << "cache: " << f.m_cache_result << ", new_child: " << f.m_new_child << ", max-depth: " << f.m_max_depth << ", i: " << f.m_i << "\n";
 | 
			
		||||
        out << "------------------\n";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -350,11 +350,13 @@ public:
 | 
			
		|||
    void update_inv_binding_at(unsigned i, expr* binding);
 | 
			
		||||
    void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
 | 
			
		||||
    void operator()(expr * t, expr_ref & result) { operator()(t, result, m_pr); }
 | 
			
		||||
    void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
 | 
			
		||||
    expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
 | 
			
		||||
        expr_ref result(m());
 | 
			
		||||
        SASSERT(!m_proof_gen);
 | 
			
		||||
        reset();
 | 
			
		||||
        set_inv_bindings(num_bindings, bindings);
 | 
			
		||||
        operator()(n, result);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resume(expr_ref & result, proof_ref & result_pr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -542,7 +542,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
 | 
			
		|||
    }
 | 
			
		||||
    result_stack().shrink(fr.m_spos);
 | 
			
		||||
    result_stack().push_back(m_r.get());
 | 
			
		||||
    SASSERT(m().is_bool(m_r));
 | 
			
		||||
    SASSERT(m().get_sort(q) == m().get_sort(m_r));
 | 
			
		||||
    if (!ProofGen) {
 | 
			
		||||
        SASSERT(num_decls <= m_bindings.size());
 | 
			
		||||
        m_bindings.shrink(m_bindings.size() - num_decls);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ expr_ref sym_expr::accept(expr* e) {
 | 
			
		|||
    switch (m_ty) {
 | 
			
		||||
    case t_pred: {
 | 
			
		||||
        var_subst subst(m);
 | 
			
		||||
        subst(m_t, 1, &e, result);
 | 
			
		||||
        result = subst(m_t, 1, &e);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case t_char:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ Author:
 | 
			
		|||
Notes:
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "ast/rewriter/th_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_params.hpp"
 | 
			
		||||
#include "ast/rewriter/bool_rewriter.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -28,10 +29,9 @@ Notes:
 | 
			
		|||
#include "ast/rewriter/pb_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/seq_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_def.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/expr_substitution.h"
 | 
			
		||||
#include "ast/ast_smt2_pp.h"
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/ast_util.h"
 | 
			
		||||
#include "ast/well_sorted.h"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -606,7 +606,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
 | 
			
		|||
        quantifier_ref q1(m());
 | 
			
		||||
        proof * p1 = nullptr;
 | 
			
		||||
        if (is_quantifier(new_body) &&
 | 
			
		||||
            to_quantifier(new_body)->is_forall() == old_q->is_forall() &&
 | 
			
		||||
            to_quantifier(new_body)->get_kind() == old_q->get_kind() &&
 | 
			
		||||
            to_quantifier(new_body)->get_kind() != lambda_k && 
 | 
			
		||||
            !old_q->has_patterns() &&
 | 
			
		||||
            !to_quantifier(new_body)->has_patterns()) {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +620,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
 | 
			
		|||
            sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
 | 
			
		||||
            names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
 | 
			
		||||
 | 
			
		||||
            q1 = m().mk_quantifier(old_q->is_forall(),
 | 
			
		||||
            q1 = m().mk_quantifier(old_q->get_kind(),
 | 
			
		||||
                                   sorts.size(),
 | 
			
		||||
                                   sorts.c_ptr(),
 | 
			
		||||
                                   names.c_ptr(),
 | 
			
		||||
| 
						 | 
				
			
			@ -653,17 +654,19 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
 | 
			
		|||
            SASSERT(is_well_sorted(m(), q1));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        elim_unused_vars(m(), q1, params_ref(), result);
 | 
			
		||||
        SASSERT(m().get_sort(old_q) == m().get_sort(q1));
 | 
			
		||||
        result = elim_unused_vars(m(), q1, params_ref());
 | 
			
		||||
 | 
			
		||||
        TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m()) << "\n";);
 | 
			
		||||
        TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";);
 | 
			
		||||
 | 
			
		||||
        result_pr = nullptr;
 | 
			
		||||
        if (m().proofs_enabled()) {
 | 
			
		||||
            proof * p2 = nullptr;
 | 
			
		||||
            if (q1.get() != result.get())
 | 
			
		||||
            if (q1.get() != result.get() && q1->get_kind() != lambda_k) 
 | 
			
		||||
                p2 = m().mk_elim_unused_vars(q1, result);
 | 
			
		||||
            result_pr = m().mk_transitivity(p1, p2);
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(m().get_sort(old_q) == m().get_sort(result));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -784,8 +787,8 @@ void th_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr)
 | 
			
		|||
    m_imp->operator()(t, result, result_pr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result) {
 | 
			
		||||
    m_imp->operator()(n, num_bindings, bindings, result);
 | 
			
		||||
expr_ref th_rewriter::operator()(expr * n, unsigned num_bindings, expr * const * bindings) {
 | 
			
		||||
    return m_imp->operator()(n, num_bindings, bindings);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void th_rewriter::set_substitution(expr_substitution * s) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ public:
 | 
			
		|||
    void operator()(expr_ref& term);
 | 
			
		||||
    void operator()(expr * t, expr_ref & result);
 | 
			
		||||
    void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
 | 
			
		||||
    void operator()(expr * n, unsigned num_bindings, expr * const * bindings, expr_ref & result);
 | 
			
		||||
    expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings);
 | 
			
		||||
 | 
			
		||||
    expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,10 +23,11 @@ Notes:
 | 
			
		|||
#include "ast/well_sorted.h"
 | 
			
		||||
#include "ast/for_each_expr.h"
 | 
			
		||||
 | 
			
		||||
void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result) {
 | 
			
		||||
expr_ref var_subst::operator()(expr * n, unsigned num_args, expr * const * args) {
 | 
			
		||||
    expr_ref result(m_reducer.m());
 | 
			
		||||
    if (is_ground(n)) {
 | 
			
		||||
        result = n;
 | 
			
		||||
        return;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(is_well_sorted(result.m(), n));
 | 
			
		||||
    m_reducer.reset();
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +42,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
 | 
			
		|||
          for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m_reducer.m()) << "\n";
 | 
			
		||||
          tout << "\n------>\n";
 | 
			
		||||
          tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const & params) :
 | 
			
		||||
| 
						 | 
				
			
			@ -49,16 +51,22 @@ unused_vars_eliminator::unused_vars_eliminator(ast_manager & m, params_ref const
 | 
			
		|||
    m_ignore_patterns_on_ground_qbody = m_params.get_bool("ignore_patterns_on_ground_qbody", true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
 | 
			
		||||
expr_ref unused_vars_eliminator::operator()(quantifier* q) {
 | 
			
		||||
    expr_ref result(m);
 | 
			
		||||
    SASSERT(is_well_sorted(m, q));
 | 
			
		||||
    TRACE("elim_unused_vars", tout << expr_ref(q, m) << "\n";);
 | 
			
		||||
    if (is_lambda(q)) {
 | 
			
		||||
        result = q;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    if (m_ignore_patterns_on_ground_qbody && is_ground(q->get_expr())) {
 | 
			
		||||
        // Ignore patterns if the body is a ground formula.
 | 
			
		||||
        result = q->get_expr();
 | 
			
		||||
        return;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    if (!q->may_have_unused_vars()) {
 | 
			
		||||
        result = q;
 | 
			
		||||
        return;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
    m_used.reset();
 | 
			
		||||
    m_used.process(q->get_expr());
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +81,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
 | 
			
		|||
    if (m_used.uses_all_vars(num_decls)) {
 | 
			
		||||
        q->set_no_unused_vars();
 | 
			
		||||
        result = q;
 | 
			
		||||
        return;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ptr_buffer<sort>  used_decl_sorts;
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +128,11 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
 | 
			
		|||
 | 
			
		||||
    expr_ref  new_expr(m);
 | 
			
		||||
 | 
			
		||||
    m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
 | 
			
		||||
    new_expr = m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr());
 | 
			
		||||
 | 
			
		||||
    if (num_removed == num_decls) {
 | 
			
		||||
        result = new_expr;
 | 
			
		||||
        return;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    expr_ref tmp(m);
 | 
			
		||||
| 
						 | 
				
			
			@ -132,15 +140,15 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
 | 
			
		|||
    expr_ref_buffer new_no_patterns(m);
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < num_patterns; i++) {
 | 
			
		||||
        m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
 | 
			
		||||
        tmp = m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr());
 | 
			
		||||
        new_patterns.push_back(tmp);
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned i = 0; i < num_no_patterns; i++) {
 | 
			
		||||
        m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
 | 
			
		||||
        tmp = m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr());
 | 
			
		||||
        new_no_patterns.push_back(tmp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = m.mk_quantifier(q->is_forall(),
 | 
			
		||||
    result = m.mk_quantifier(q->get_kind(),
 | 
			
		||||
                             used_decl_sorts.size(),
 | 
			
		||||
                             used_decl_sorts.c_ptr(),
 | 
			
		||||
                             used_decl_names.c_ptr(),
 | 
			
		||||
| 
						 | 
				
			
			@ -154,24 +162,28 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
 | 
			
		|||
                             new_no_patterns.c_ptr());
 | 
			
		||||
    to_quantifier(result)->set_no_unused_vars();
 | 
			
		||||
    SASSERT(is_well_sorted(m, result));
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & result) {
 | 
			
		||||
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params) {
 | 
			
		||||
    unused_vars_eliminator el(m, params);
 | 
			
		||||
    el(q, result);
 | 
			
		||||
    expr_ref result = el(q);
 | 
			
		||||
    TRACE("elim_unused_vars", tout << expr_ref(q, m) << " -> " << result << "\n";);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
 | 
			
		||||
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs) {
 | 
			
		||||
    var_subst subst(m);
 | 
			
		||||
    expr_ref new_expr(m);
 | 
			
		||||
    subst(q->get_expr(), q->get_num_decls(), exprs, new_expr);
 | 
			
		||||
    TRACE("var_subst", tout << mk_pp(q, m) << "\n" << mk_pp(new_expr, m) << "\n";);
 | 
			
		||||
    expr_ref new_expr(m), result(m);
 | 
			
		||||
    new_expr = subst(q->get_expr(), q->get_num_decls(), exprs);
 | 
			
		||||
    TRACE("var_subst", tout << mk_pp(q, m) << "\n" << new_expr << "\n";);
 | 
			
		||||
    inv_var_shifter shift(m);
 | 
			
		||||
    shift(new_expr, q->get_num_decls(), result);
 | 
			
		||||
    SASSERT(is_well_sorted(m, result));
 | 
			
		||||
    TRACE("instantiate_bug", tout << mk_ismt2_pp(q, m) << "\nusing\n";
 | 
			
		||||
          for (unsigned i = 0; i < q->get_num_decls(); i++) tout << mk_ismt2_pp(exprs[i], m) << "\n";
 | 
			
		||||
          tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void get_free_vars_offset(expr_sparse_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ public:
 | 
			
		|||
 | 
			
		||||
       Otherwise, (VAR 0) is stored in the first position, (VAR 1) in the second, and so on.
 | 
			
		||||
    */
 | 
			
		||||
    void operator()(expr * n, unsigned num_args, expr * const * args, expr_ref & result);
 | 
			
		||||
    expr_ref operator()(expr * n, unsigned num_args, expr * const * args);
 | 
			
		||||
    void reset() { m_reducer.reset(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -63,10 +63,10 @@ class unused_vars_eliminator {
 | 
			
		|||
    bool          m_ignore_patterns_on_ground_qbody;
 | 
			
		||||
public:
 | 
			
		||||
    unused_vars_eliminator(ast_manager & m, params_ref const & params);
 | 
			
		||||
    void operator()(quantifier* q, expr_ref& r);
 | 
			
		||||
    expr_ref operator()(quantifier* q);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params, expr_ref & r);
 | 
			
		||||
expr_ref elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   \brief Instantiate quantifier q using the given exprs.
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, params_ref const & params
 | 
			
		|||
   ...
 | 
			
		||||
   (VAR (q->get_num_decls() - 1)) is stored in the first position of the array.
 | 
			
		||||
*/
 | 
			
		||||
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result);
 | 
			
		||||
expr_ref instantiate(ast_manager & m, quantifier * q, expr * const * exprs);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   \brief Enumerate set of free variables in expression.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,9 +35,10 @@ struct well_sorted_proc {
 | 
			
		|||
 | 
			
		||||
    void operator()(quantifier * n) {
 | 
			
		||||
        expr const * e  = n->get_expr();
 | 
			
		||||
        if (!m_manager.is_bool(e)) {
 | 
			
		||||
        if (!is_lambda(n) && !m_manager.is_bool(e)) {
 | 
			
		||||
            warning_msg("quantifier's body must be a boolean.");
 | 
			
		||||
            m_error = true;
 | 
			
		||||
            UNREACHABLE();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1070,7 +1070,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg
 | 
			
		|||
              tout << "body:\n" << mk_ismt2_pp(_t, m()) << "\n";
 | 
			
		||||
              tout << "args:\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n" << mk_pp(m().get_sort(args[i]), m()) << "\n";);
 | 
			
		||||
        var_subst subst(m());
 | 
			
		||||
        subst(_t, num_args, args, result);
 | 
			
		||||
        result = subst(_t, num_args, args);
 | 
			
		||||
        if (well_sorted_check_enabled() && !is_well_sorted(m(), result))
 | 
			
		||||
            throw cmd_exception("invalid macro application, sort mismatch ", s);
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1625,6 +1625,7 @@ void cmd_context::display_dimacs() {
 | 
			
		|||
void cmd_context::display_model(model_ref& mdl) {
 | 
			
		||||
    if (mdl) {
 | 
			
		||||
        if (m_mc0) (*m_mc0)(mdl);
 | 
			
		||||
        if (m_params.m_model_compress) mdl->compress();
 | 
			
		||||
        model_params p;
 | 
			
		||||
        if (p.v1() || p.v2()) {
 | 
			
		||||
            std::ostringstream buffer;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ context_params::context_params() {
 | 
			
		|||
    m_debug_ref_count = false;
 | 
			
		||||
    m_smtlib2_compliant = false;
 | 
			
		||||
    m_well_sorted_check = false;
 | 
			
		||||
    m_model_compress = true;
 | 
			
		||||
    m_timeout = UINT_MAX;
 | 
			
		||||
    m_rlimit  = 0;
 | 
			
		||||
    updt_params();
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +103,9 @@ void context_params::set(char const * param, char const * value) {
 | 
			
		|||
    else if (p == "model_validate") {
 | 
			
		||||
        set_bool(m_model_validate, param, value);
 | 
			
		||||
    }
 | 
			
		||||
    else if (p == "model_compress") {
 | 
			
		||||
        set_bool(m_model_compress, param, value);
 | 
			
		||||
    }
 | 
			
		||||
    else if (p == "dump_models") {
 | 
			
		||||
        set_bool(m_dump_models, param, value);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -146,6 +150,7 @@ void context_params::updt_params(params_ref const & p) {
 | 
			
		|||
    m_proof             = p.get_bool("proof", m_proof);
 | 
			
		||||
    m_model             = p.get_bool("model", m_model);
 | 
			
		||||
    m_model_validate    = p.get_bool("model_validate", m_model_validate);
 | 
			
		||||
    m_model_compress    = p.get_bool("model_compress", m_model_compress);
 | 
			
		||||
    m_dump_models       = p.get_bool("dump_models", m_dump_models);
 | 
			
		||||
    m_trace             = p.get_bool("trace", m_trace);
 | 
			
		||||
    m_trace_file_name   = p.get_str("trace_file_name", "z3.log");
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +167,7 @@ void context_params::collect_param_descrs(param_descrs & d) {
 | 
			
		|||
    d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
 | 
			
		||||
    d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
 | 
			
		||||
    d.insert("model_validate", CPK_BOOL, "validate models produced by solvers", "false");
 | 
			
		||||
    d.insert("model_compress", CPK_BOOL, "compress models for easier consumption", "true");
 | 
			
		||||
    d.insert("dump_models", CPK_BOOL, "dump models whenever check-sat returns sat", "false");
 | 
			
		||||
    d.insert("trace", CPK_BOOL, "trace generation for VCC", "false");
 | 
			
		||||
    d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ public:
 | 
			
		|||
    bool        m_well_sorted_check;
 | 
			
		||||
    bool        m_model;
 | 
			
		||||
    bool        m_model_validate;
 | 
			
		||||
    bool        m_model_compress;
 | 
			
		||||
    bool        m_dump_models;
 | 
			
		||||
    bool        m_unsat_core;
 | 
			
		||||
    bool        m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,9 +135,8 @@ public:
 | 
			
		|||
        m_idx++;
 | 
			
		||||
    }
 | 
			
		||||
    void execute(cmd_context & ctx) override {
 | 
			
		||||
        expr_ref r(ctx.m());
 | 
			
		||||
        beta_reducer p(ctx.m());
 | 
			
		||||
        p(m_source, m_subst.size(), m_subst.c_ptr(), r);
 | 
			
		||||
        expr_ref r = p(m_source, m_subst.size(), m_subst.c_ptr());
 | 
			
		||||
        store_expr_ref(ctx, m_target, r.get());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -274,8 +273,7 @@ UNARY_CMD(elim_unused_vars_cmd, "dbg-elim-unused-vars", "<expr>", "eliminate unu
 | 
			
		|||
        ctx.display(ctx.regular_stream(), arg);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    expr_ref r(ctx.m());
 | 
			
		||||
    elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref(), r);
 | 
			
		||||
    expr_ref r = elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref());
 | 
			
		||||
    SASSERT(!is_quantifier(r) || !to_quantifier(r)->may_have_unused_vars());
 | 
			
		||||
    ctx.display(ctx.regular_stream(), r);
 | 
			
		||||
    ctx.regular_stream() << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -307,8 +305,7 @@ public:
 | 
			
		|||
        if (num != m_q->get_num_decls())
 | 
			
		||||
            throw cmd_exception("invalid command, mismatch between the number of quantified variables and the number of arguments.");
 | 
			
		||||
        unsigned i = num;
 | 
			
		||||
        while (i > 0) {
 | 
			
		||||
            --i;
 | 
			
		||||
        while (i-- > 0) {
 | 
			
		||||
            sort * s = ctx.m().get_sort(ts[i]);
 | 
			
		||||
            if (s != m_q->get_decl_sort(i)) {
 | 
			
		||||
                std::ostringstream buffer;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,8 +317,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void execute(cmd_context & ctx) override {
 | 
			
		||||
        expr_ref r(ctx.m());
 | 
			
		||||
        instantiate(ctx.m(), m_q, m_args.c_ptr(), r);
 | 
			
		||||
        expr_ref r = instantiate(ctx.m(), m_q, m_args.c_ptr());
 | 
			
		||||
        ctx.display(ctx.regular_stream(), r);
 | 
			
		||||
        ctx.regular_stream() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,11 +15,12 @@ Author:
 | 
			
		|||
Revision History:
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "model/func_interp.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "util/obj_hashtable.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/ast_smt2_pp.h"
 | 
			
		||||
#include "ast/ast_util.h"
 | 
			
		||||
#include "model/func_interp.h"
 | 
			
		||||
 | 
			
		||||
func_entry::func_entry(ast_manager & m, unsigned arity, expr * const * args, expr * result):
 | 
			
		||||
    m_args_are_values(true),
 | 
			
		||||
| 
						 | 
				
			
			@ -77,10 +78,7 @@ func_interp::func_interp(ast_manager & m, unsigned arity):
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func_interp::~func_interp() {
 | 
			
		||||
    ptr_vector<func_entry>::iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry* curr : m_entries) {
 | 
			
		||||
        curr->deallocate(m_manager, m_arity);
 | 
			
		||||
    }
 | 
			
		||||
    m_manager.dec_ref(m_else);
 | 
			
		||||
| 
						 | 
				
			
			@ -90,10 +88,7 @@ func_interp::~func_interp() {
 | 
			
		|||
func_interp * func_interp::copy() const {
 | 
			
		||||
    func_interp * new_fi = alloc(func_interp, m_manager, m_arity);
 | 
			
		||||
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        new_fi->insert_new_entry(curr->get_args(), curr->get_result());
 | 
			
		||||
    }
 | 
			
		||||
    new_fi->set_else(m_else);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,9 +136,11 @@ void func_interp::set_else(expr * e) {
 | 
			
		|||
        return;
 | 
			
		||||
 | 
			
		||||
    reset_interp_cache();
 | 
			
		||||
 | 
			
		||||
    TRACE("func_interp", tout << "set_else: " << expr_ref(e, m()) << "\n";);
 | 
			
		||||
 | 
			
		||||
    ptr_vector<expr> args;
 | 
			
		||||
    while (e && is_fi_entry_expr(e, args)) {
 | 
			
		||||
        TRACE("func_interp", tout << "fi entry expr: " << mk_ismt2_pp(e, m()) << std::endl;);
 | 
			
		||||
        insert_entry(args.c_ptr(), to_app(e)->get_arg(1));
 | 
			
		||||
        e = to_app(e)->get_arg(2);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -161,10 +158,7 @@ bool func_interp::is_constant() const {
 | 
			
		|||
        return false;
 | 
			
		||||
    if (!is_ground(m_else))
 | 
			
		||||
        return false;
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry* curr : m_entries) {
 | 
			
		||||
        if (curr->get_result() != m_else)
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -177,10 +171,7 @@ bool func_interp::is_constant() const {
 | 
			
		|||
   args_are_values to true if for all entries e e.args_are_values() is true.
 | 
			
		||||
*/
 | 
			
		||||
func_entry * func_interp::get_entry(expr * const * args) const {
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry* curr : m_entries) {
 | 
			
		||||
        if (curr->eq_args(m(), m_arity, args))
 | 
			
		||||
            return curr;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -224,7 +215,7 @@ bool func_interp::eval_else(expr * const * args, expr_ref & result) const {
 | 
			
		|||
        return false;
 | 
			
		||||
    var_subst s(m_manager, false);
 | 
			
		||||
    SASSERT(!s.std_order()); // (VAR 0) <- args[0], (VAR 1) <- args[1], ...
 | 
			
		||||
    s(m_else, m_arity, args, result);
 | 
			
		||||
    result = s(m_else, m_arity, args);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -237,10 +228,7 @@ expr * func_interp::get_max_occ_result() const {
 | 
			
		|||
    obj_map<expr, unsigned> num_occs;
 | 
			
		||||
    expr *   r_max = nullptr;
 | 
			
		||||
    unsigned max   = 0;
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        expr * r = curr->get_result();
 | 
			
		||||
        unsigned occs = 0;
 | 
			
		||||
        num_occs.find(r, occs);
 | 
			
		||||
| 
						 | 
				
			
			@ -262,15 +250,11 @@ void func_interp::compress() {
 | 
			
		|||
        return; // nothing to be done
 | 
			
		||||
    if (!is_ground(m_else))
 | 
			
		||||
        return; // forall entries e in m_entries e.get_result() is ground
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    unsigned j = 0;
 | 
			
		||||
    unsigned sz = m_entries.size();
 | 
			
		||||
    m_args_are_values = true;
 | 
			
		||||
    for (; i < sz; i++) {
 | 
			
		||||
        func_entry * curr = m_entries[i];
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        if (curr->get_result() != m_else) {
 | 
			
		||||
            m_entries[j] = curr;
 | 
			
		||||
            j++;
 | 
			
		||||
            m_entries[j++] = curr;
 | 
			
		||||
            if (!curr->args_are_values())
 | 
			
		||||
                m_args_are_values = false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -278,10 +262,58 @@ void func_interp::compress() {
 | 
			
		|||
            curr->deallocate(m_manager, m_arity);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (j < sz) {
 | 
			
		||||
    if (j < m_entries.size()) {
 | 
			
		||||
        reset_interp_cache();
 | 
			
		||||
        m_entries.shrink(j);
 | 
			
		||||
    }
 | 
			
		||||
    // other compression, if else is a default branch.
 | 
			
		||||
    // or function encode identity.
 | 
			
		||||
    if (m_manager.is_false(m_else)) {
 | 
			
		||||
        expr_ref new_else(get_interp(), m_manager);
 | 
			
		||||
        for (func_entry * curr : m_entries) {
 | 
			
		||||
            curr->deallocate(m_manager, m_arity);
 | 
			
		||||
        }
 | 
			
		||||
        m_entries.reset();
 | 
			
		||||
        reset_interp_cache();
 | 
			
		||||
        m_manager.inc_ref(new_else);
 | 
			
		||||
        m_manager.dec_ref(m_else);
 | 
			
		||||
        m_else = new_else;
 | 
			
		||||
    }
 | 
			
		||||
    else if (!m_entries.empty() && is_identity()) {
 | 
			
		||||
        for (func_entry * curr : m_entries) {
 | 
			
		||||
            curr->deallocate(m_manager, m_arity);
 | 
			
		||||
        }
 | 
			
		||||
        m_entries.reset();
 | 
			
		||||
        reset_interp_cache();
 | 
			
		||||
        expr_ref new_else(m_manager.mk_var(0, m_manager.get_sort(m_else)), m_manager);
 | 
			
		||||
        m_manager.inc_ref(new_else);
 | 
			
		||||
        m_manager.dec_ref(m_else);
 | 
			
		||||
        m_else = new_else;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief check if function is identity
 | 
			
		||||
 */
 | 
			
		||||
bool func_interp::is_identity() const {
 | 
			
		||||
    if (m_arity != 1) return false;
 | 
			
		||||
    if (m_else == nullptr) return false;
 | 
			
		||||
 | 
			
		||||
    // all entries map a value to itself
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        if (curr->get_arg(0) != curr->get_result()) return false;
 | 
			
		||||
        if (curr->get_result() == m_else) return false;
 | 
			
		||||
    }    
 | 
			
		||||
    if (is_var(m_else)) return true;
 | 
			
		||||
    if (!m_manager.is_value(m_else)) return false;    
 | 
			
		||||
    sort_size const& sz = m_manager.get_sort(m_else)->get_num_elements();
 | 
			
		||||
    if (!sz.is_finite()) return false;
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // the else entry is a value not covered by other entries
 | 
			
		||||
    // it, together with the entries covers the entire domain.
 | 
			
		||||
    //
 | 
			
		||||
    return (sz.size() == m_entries.size() + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr * func_interp::get_interp_core() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -289,10 +321,10 @@ expr * func_interp::get_interp_core() const {
 | 
			
		|||
        return nullptr;
 | 
			
		||||
    expr * r = m_else;
 | 
			
		||||
    ptr_buffer<expr> vars;
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        if (m_else == curr->get_result()) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        if (vars.empty()) {
 | 
			
		||||
            for (unsigned i = 0; i < m_arity; i++) {
 | 
			
		||||
                vars.push_back(m_manager.mk_var(i, m_manager.get_sort(curr->get_arg(i))));
 | 
			
		||||
| 
						 | 
				
			
			@ -303,12 +335,17 @@ expr * func_interp::get_interp_core() const {
 | 
			
		|||
            eqs.push_back(m_manager.mk_eq(vars[i], curr->get_arg(i)));
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(eqs.size() == m_arity);
 | 
			
		||||
        expr * cond;
 | 
			
		||||
        if (m_arity == 1)
 | 
			
		||||
            cond = eqs.get(0);
 | 
			
		||||
        else
 | 
			
		||||
            cond = m_manager.mk_and(eqs.size(), eqs.c_ptr());
 | 
			
		||||
        r = m_manager.mk_ite(cond, curr->get_result(), r);
 | 
			
		||||
        expr * cond = mk_and(m_manager, eqs.size(), eqs.c_ptr());
 | 
			
		||||
        expr * th = curr->get_result();
 | 
			
		||||
        if (m_manager.is_true(th)) {
 | 
			
		||||
            r = m_manager.mk_or(cond, r);
 | 
			
		||||
        }
 | 
			
		||||
        else if (m_manager.is_false(th)) {
 | 
			
		||||
            r = m_manager.mk_and(m_manager.mk_not(cond), r);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            r = m_manager.mk_ite(cond, th, r);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -327,12 +364,9 @@ expr * func_interp::get_interp() const {
 | 
			
		|||
func_interp * func_interp::translate(ast_translation & translator) const {
 | 
			
		||||
    func_interp * new_fi = alloc(func_interp, translator.to(), m_arity);
 | 
			
		||||
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator it  = m_entries.begin();
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end = m_entries.end();
 | 
			
		||||
    for (; it != end; ++it) {
 | 
			
		||||
        func_entry * curr = *it;
 | 
			
		||||
    for (func_entry * curr : m_entries) {
 | 
			
		||||
        ptr_buffer<expr> new_args;
 | 
			
		||||
        for (unsigned i=0; i<m_arity; i++)
 | 
			
		||||
        for (unsigned i = 0; i < m_arity; i++)
 | 
			
		||||
            new_args.push_back(translator(curr->get_arg(i)));
 | 
			
		||||
        new_fi->insert_new_entry(new_args.c_ptr(), translator(curr->get_result()));
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,7 @@ public:
 | 
			
		|||
    expr * get_result() const { return m_result; }
 | 
			
		||||
    expr * get_arg(unsigned idx) const { return m_args[idx]; }
 | 
			
		||||
    expr * const * get_args() const { return m_args; }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
       \brief Return true if m.are_equal(m_args[i], args[i]) for all i in [0, arity)
 | 
			
		||||
    */
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +102,8 @@ public:
 | 
			
		|||
    func_entry * get_entry(expr * const * args) const;
 | 
			
		||||
    bool eval_else(expr * const * args, expr_ref & result) const;
 | 
			
		||||
    unsigned num_entries() const { return m_entries.size(); }
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator begin() const { return m_entries.begin(); }
 | 
			
		||||
    ptr_vector<func_entry>::const_iterator end() const { return m_entries.end(); }
 | 
			
		||||
    func_entry const * const * get_entries() const { return m_entries.c_ptr(); }
 | 
			
		||||
    func_entry const * get_entry(unsigned idx) const { return m_entries[idx]; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +116,7 @@ public:
 | 
			
		|||
 | 
			
		||||
private:
 | 
			
		||||
    bool is_fi_entry_expr(expr * e, ptr_vector<expr> & args);
 | 
			
		||||
    bool is_identity() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,34 +16,36 @@ Author:
 | 
			
		|||
Revision History:
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "model/model.h"
 | 
			
		||||
#include "util/top_sort.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/ast_ll_pp.h"
 | 
			
		||||
#include "ast/rewriter/var_subst.h"
 | 
			
		||||
#include "ast/rewriter/th_rewriter.h"
 | 
			
		||||
#include "ast/array_decl_plugin.h"
 | 
			
		||||
#include "ast/well_sorted.h"
 | 
			
		||||
#include "ast/used_symbols.h"
 | 
			
		||||
#include "ast/for_each_expr.h"
 | 
			
		||||
#include "ast/for_each_ast.h"
 | 
			
		||||
#include "model/model.h"
 | 
			
		||||
#include "model/model_evaluator.h"
 | 
			
		||||
 | 
			
		||||
model::model(ast_manager & m):
 | 
			
		||||
    model_core(m),
 | 
			
		||||
    m_mev(*this) {
 | 
			
		||||
    m_mev(*this),
 | 
			
		||||
    m_cleaned(false) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::~model() {
 | 
			
		||||
    for (auto & kv : m_usort2universe) {
 | 
			
		||||
        m_manager.dec_ref(kv.m_key);
 | 
			
		||||
        m_manager.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
 | 
			
		||||
        m.dec_ref(kv.m_key);
 | 
			
		||||
        m.dec_array_ref(kv.m_value->size(), kv.m_value->c_ptr());
 | 
			
		||||
        dealloc(kv.m_value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void model::copy_const_interps(model const & source) {
 | 
			
		||||
    for (auto const& kv : source.m_interp) {
 | 
			
		||||
    for (auto const& kv : source.m_interp) 
 | 
			
		||||
        register_decl(kv.m_key, kv.m_value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::copy_func_interps(model const & source) {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,13 +59,11 @@ void model::copy_usort_interps(model const & source) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
model * model::copy() const {
 | 
			
		||||
    model * m = alloc(model, m_manager);
 | 
			
		||||
 | 
			
		||||
    m->copy_const_interps(*this);
 | 
			
		||||
    m->copy_func_interps(*this);
 | 
			
		||||
    m->copy_usort_interps(*this);
 | 
			
		||||
 | 
			
		||||
    return m;
 | 
			
		||||
    model * mdl = alloc(model, m);
 | 
			
		||||
    mdl->copy_const_interps(*this);
 | 
			
		||||
    mdl->copy_func_interps(*this);
 | 
			
		||||
    mdl->copy_usort_interps(*this);
 | 
			
		||||
    return mdl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool model::eval_expr(expr * e, expr_ref & result, bool model_completion) {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,13 +94,13 @@ struct model::value_proc : public some_value_proc {
 | 
			
		|||
 | 
			
		||||
expr * model::get_some_value(sort * s) {
 | 
			
		||||
    value_proc p(*this);
 | 
			
		||||
    return m_manager.get_some_value(s, &p);
 | 
			
		||||
    return m.get_some_value(s, &p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ptr_vector<expr> const & model::get_universe(sort * s) const {
 | 
			
		||||
    ptr_vector<expr> * u = nullptr;
 | 
			
		||||
    m_usort2universe.find(s, u);
 | 
			
		||||
    SASSERT(u != 0);
 | 
			
		||||
    SASSERT(u != nullptr);
 | 
			
		||||
    return *u;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +120,11 @@ sort * model::get_uninterpreted_sort(unsigned idx) const {
 | 
			
		|||
 | 
			
		||||
void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
 | 
			
		||||
    sort2universe::obj_map_entry * entry = m_usort2universe.insert_if_not_there2(s, 0);
 | 
			
		||||
    m_manager.inc_array_ref(usize, universe);
 | 
			
		||||
    m.inc_array_ref(usize, universe);
 | 
			
		||||
    if (entry->get_data().m_value == 0) {
 | 
			
		||||
        // new entry
 | 
			
		||||
        m_usorts.push_back(s);
 | 
			
		||||
        m_manager.inc_ref(s);
 | 
			
		||||
        m.inc_ref(s);
 | 
			
		||||
        ptr_vector<expr> * new_u = alloc(ptr_vector<expr>);
 | 
			
		||||
        new_u->append(usize, universe);
 | 
			
		||||
        entry->get_data().m_value = new_u;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,7 +133,7 @@ void model::register_usort(sort * s, unsigned usize, expr * const * universe) {
 | 
			
		|||
        // updating
 | 
			
		||||
        ptr_vector<expr> * u = entry->get_data().m_value;
 | 
			
		||||
        SASSERT(u);
 | 
			
		||||
        m_manager.dec_array_ref(u->size(), u->c_ptr());
 | 
			
		||||
        m.dec_array_ref(u->size(), u->c_ptr());
 | 
			
		||||
        u->append(usize, universe);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -154,8 +154,8 @@ model * model::translate(ast_translation & translator) const {
 | 
			
		|||
    // Translate usort interps
 | 
			
		||||
    for (auto const& kv : m_usort2universe) {
 | 
			
		||||
        ptr_vector<expr> new_universe;
 | 
			
		||||
        for (unsigned i=0; i < kv.m_value->size(); i++)
 | 
			
		||||
            new_universe.push_back(translator(kv.m_value->get(i)));
 | 
			
		||||
        for (expr* e : *kv.m_value) 
 | 
			
		||||
            new_universe.push_back(translator(e));
 | 
			
		||||
        res->register_usort(translator(kv.m_key),
 | 
			
		||||
                            new_universe.size(),
 | 
			
		||||
                            new_universe.c_ptr());
 | 
			
		||||
| 
						 | 
				
			
			@ -164,22 +164,322 @@ model * model::translate(ast_translation & translator) const {
 | 
			
		|||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct model::top_sort : public ::top_sort<func_decl> {
 | 
			
		||||
    th_rewriter                  m_rewrite;
 | 
			
		||||
    obj_map<func_decl, unsigned> m_occur_count;
 | 
			
		||||
 | 
			
		||||
    top_sort(ast_manager& m):
 | 
			
		||||
        m_rewrite(m)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void add_occurs(func_decl* f) {
 | 
			
		||||
        m_occur_count.insert(f, occur_count(f) + 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned occur_count(func_decl* f) const {
 | 
			
		||||
        unsigned count = 0;
 | 
			
		||||
        m_occur_count.find(f, count);
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~top_sort() override {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void model::compress() {
 | 
			
		||||
    if (m_cleaned) return;
 | 
			
		||||
 | 
			
		||||
    // stratify m_finterp and m_decls in a topological sort
 | 
			
		||||
    // such that functions f1 < f2 then f1 does not use f2.
 | 
			
		||||
    // then for each function in order clean-up the interpretations
 | 
			
		||||
    // by substituting in auxiliary definitions that can be eliminated.
 | 
			
		||||
 | 
			
		||||
    func_decl_ref_vector pinned(m);
 | 
			
		||||
    while (true) {
 | 
			
		||||
        top_sort ts(m);
 | 
			
		||||
        collect_deps(ts);
 | 
			
		||||
        ts.topological_sort();
 | 
			
		||||
        for (func_decl * f : ts.top_sorted()) {
 | 
			
		||||
            cleanup_interp(ts, f);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        func_decl_set removed;
 | 
			
		||||
        ts.m_occur_count.reset();
 | 
			
		||||
        for (func_decl * f : ts.top_sorted()) {
 | 
			
		||||
            collect_occs(ts, f);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // remove auxiliary declarations that are not used.
 | 
			
		||||
        for (func_decl * f : ts.top_sorted()) {
 | 
			
		||||
            if (f->is_skolem() && ts.occur_count(f) == 0) {
 | 
			
		||||
                pinned.push_back(f);
 | 
			
		||||
                unregister_decl(f);
 | 
			
		||||
                removed.insert(f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (removed.empty()) break;
 | 
			
		||||
        remove_decls(m_decls, removed);
 | 
			
		||||
        remove_decls(m_func_decls, removed);
 | 
			
		||||
        remove_decls(m_const_decls, removed);
 | 
			
		||||
    }
 | 
			
		||||
    m_cleaned = true;
 | 
			
		||||
    reset_eval_cache();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void model::collect_deps(top_sort& ts) {
 | 
			
		||||
    for (auto const& kv : m_finterp) {
 | 
			
		||||
        ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
 | 
			
		||||
    }
 | 
			
		||||
    for (auto const& kv : m_interp) {
 | 
			
		||||
        ts.insert(kv.m_key, collect_deps(ts, kv.m_value));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct model::deps_collector {
 | 
			
		||||
    model&         m;
 | 
			
		||||
    top_sort&      ts;
 | 
			
		||||
    func_decl_set& s;
 | 
			
		||||
    array_util     autil;
 | 
			
		||||
    deps_collector(model& m, top_sort& ts, func_decl_set& s): m(m), ts(ts), s(s), autil(m.get_manager()) {}
 | 
			
		||||
    void operator()(app* a) {
 | 
			
		||||
        func_decl* f = a->get_decl();
 | 
			
		||||
        if (autil.is_as_array(f)) {
 | 
			
		||||
            f = autil.get_as_array_func_decl(a);            
 | 
			
		||||
        }
 | 
			
		||||
        if (m.has_interpretation(f)) {
 | 
			
		||||
            s.insert(f);
 | 
			
		||||
            ts.add_occurs(f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    void operator()(expr* ) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct model::occs_collector {
 | 
			
		||||
    top_sort&      ts;
 | 
			
		||||
    occs_collector(top_sort& ts): ts(ts) {}
 | 
			
		||||
    void operator()(func_decl* f) {
 | 
			
		||||
        ts.add_occurs(f);
 | 
			
		||||
    }
 | 
			
		||||
    void operator()(ast* ) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
model::func_decl_set* model::collect_deps(top_sort& ts, expr * e) {
 | 
			
		||||
    func_decl_set* s = alloc(func_decl_set);
 | 
			
		||||
    deps_collector collector(*this, ts, *s);
 | 
			
		||||
    if (e) for_each_expr(collector, e);
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
model::func_decl_set* model::collect_deps(top_sort& ts, func_interp * fi) {
 | 
			
		||||
    func_decl_set* s = alloc(func_decl_set);
 | 
			
		||||
    deps_collector collector(*this, ts, *s);
 | 
			
		||||
    fi->compress();
 | 
			
		||||
    expr* e = fi->get_else();
 | 
			
		||||
    if (e) for_each_expr(collector, e);
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   \brief Inline interpretations of skolem functions
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
void model::cleanup_interp(top_sort& ts, func_decl* f) {
 | 
			
		||||
    unsigned pid = ts.partition_id(f);
 | 
			
		||||
    expr * e1 = get_const_interp(f);
 | 
			
		||||
    if (e1) {
 | 
			
		||||
        expr_ref e2 = cleanup_expr(ts, e1, pid);
 | 
			
		||||
        if (e2 != e1) 
 | 
			
		||||
            register_decl(f, e2);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    func_interp* fi = get_func_interp(f);
 | 
			
		||||
    if (fi) {
 | 
			
		||||
        e1 = fi->get_else();
 | 
			
		||||
        expr_ref e2 = cleanup_expr(ts, e1, pid);
 | 
			
		||||
        if (e1 != e2) 
 | 
			
		||||
            fi->set_else(e2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::collect_occs(top_sort& ts, func_decl* f) {
 | 
			
		||||
    expr * e = get_const_interp(f);
 | 
			
		||||
    if (e) {
 | 
			
		||||
        collect_occs(ts, e);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        func_interp* fi = get_func_interp(f);
 | 
			
		||||
        if (fi) {
 | 
			
		||||
            e = fi->get_else();
 | 
			
		||||
            collect_occs(ts, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::collect_occs(top_sort& ts, expr* e) {
 | 
			
		||||
    occs_collector collector(ts);
 | 
			
		||||
    for_each_ast(collector, e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool model::can_inline_def(top_sort& ts, func_decl* f) {
 | 
			
		||||
    if (ts.occur_count(f) <= 1) return true;
 | 
			
		||||
    func_interp* fi = get_func_interp(f);
 | 
			
		||||
    if (!fi) return false;
 | 
			
		||||
    if (fi->get_else() == nullptr) return false;
 | 
			
		||||
    expr* e = fi->get_else();
 | 
			
		||||
    obj_hashtable<expr> subs;
 | 
			
		||||
    ptr_buffer<expr> todo;
 | 
			
		||||
    todo.push_back(e);
 | 
			
		||||
    while (!todo.empty()) {
 | 
			
		||||
        if (fi->num_entries() + subs.size() > 8) return false;
 | 
			
		||||
        expr* e = todo.back();
 | 
			
		||||
        todo.pop_back();
 | 
			
		||||
        if (subs.contains(e)) continue;
 | 
			
		||||
        subs.insert(e);
 | 
			
		||||
        if (is_app(e)) {
 | 
			
		||||
            for (expr* arg : *to_app(e)) {
 | 
			
		||||
                todo.push_back(arg);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (is_quantifier(e)) {
 | 
			
		||||
            todo.push_back(to_quantifier(e)->get_expr());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
expr_ref model::cleanup_expr(top_sort& ts, expr* e, unsigned current_partition) {
 | 
			
		||||
    if (!e) return expr_ref(0, m);
 | 
			
		||||
 | 
			
		||||
    TRACE("model", tout << "cleaning up:\n" << mk_pp(e, m) << "\n";);
 | 
			
		||||
 | 
			
		||||
    obj_map<expr, expr*> cache;
 | 
			
		||||
    expr_ref_vector trail(m);
 | 
			
		||||
    ptr_buffer<expr, 128> todo;
 | 
			
		||||
    ptr_buffer<expr> args;
 | 
			
		||||
    todo.push_back(e);
 | 
			
		||||
    array_util autil(m);
 | 
			
		||||
    func_interp* fi = nullptr;
 | 
			
		||||
    unsigned pid = 0;
 | 
			
		||||
    expr_ref new_t(m);
 | 
			
		||||
 | 
			
		||||
    while (!todo.empty()) {
 | 
			
		||||
        expr* a = todo.back();
 | 
			
		||||
        switch(a->get_kind()) {
 | 
			
		||||
        case AST_APP: {
 | 
			
		||||
            app * t = to_app(a);
 | 
			
		||||
            func_decl* f = t->get_decl();
 | 
			
		||||
            bool visited = true;
 | 
			
		||||
            
 | 
			
		||||
            args.reset();
 | 
			
		||||
            for (expr* t_arg : *t) {
 | 
			
		||||
                expr * arg = nullptr;
 | 
			
		||||
                if (!cache.find(t_arg, arg)) {
 | 
			
		||||
                    visited = false;
 | 
			
		||||
                    todo.push_back(t_arg);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    args.push_back(arg);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (!visited) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            fi = nullptr;
 | 
			
		||||
            if (autil.is_as_array(a)) {
 | 
			
		||||
                func_decl* f = autil.get_as_array_func_decl(a);
 | 
			
		||||
                // only expand auxiliary definitions that occur once.
 | 
			
		||||
                if (can_inline_def(ts, f)) {
 | 
			
		||||
                    fi = get_func_interp(f);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (fi && fi->get_interp()) {
 | 
			
		||||
                f = autil.get_as_array_func_decl(a);
 | 
			
		||||
                expr_ref_vector sargs(m);
 | 
			
		||||
                sort_ref_vector vars(m);
 | 
			
		||||
                svector<symbol> var_names;
 | 
			
		||||
                for (unsigned i = 0; i < f->get_arity(); ++i) {
 | 
			
		||||
                    var_names.push_back(symbol(i));
 | 
			
		||||
                    vars.push_back(f->get_domain(f->get_arity() - i - 1));
 | 
			
		||||
                }
 | 
			
		||||
                new_t = m.mk_lambda(vars.size(), vars.c_ptr(), var_names.c_ptr(), fi->get_interp());
 | 
			
		||||
            }
 | 
			
		||||
            else if (f->is_skolem() && can_inline_def(ts, f) && (fi = get_func_interp(f)) && 
 | 
			
		||||
                     fi->get_interp() && (!ts.partition_ids().find(f, pid) || pid != current_partition)) {
 | 
			
		||||
                var_subst vs(m);
 | 
			
		||||
                // ? TBD args.reverse();
 | 
			
		||||
                new_t = vs(fi->get_interp(), args.size(), args.c_ptr());
 | 
			
		||||
            }
 | 
			
		||||
#if 0
 | 
			
		||||
            else if (is_uninterp_const(a) && !get_const_interp(f)) {
 | 
			
		||||
                new_t = get_some_value(f->get_range());
 | 
			
		||||
                register_decl(f, new_t);                
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
            else {
 | 
			
		||||
                new_t = ts.m_rewrite.mk_app(f, args.size(), args.c_ptr());
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (t != new_t.get()) trail.push_back(new_t);
 | 
			
		||||
            todo.pop_back();
 | 
			
		||||
            cache.insert(t, new_t);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(a != nullptr);
 | 
			
		||||
            cache.insert(a, a);
 | 
			
		||||
            todo.pop_back();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ts.m_rewrite(cache[e], new_t);
 | 
			
		||||
    return new_t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model::remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s) {
 | 
			
		||||
    unsigned j = 0;
 | 
			
		||||
    for (func_decl* f : decls) {
 | 
			
		||||
        if (!s.contains(f)) {
 | 
			
		||||
            decls[j++] = f;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    decls.shrink(j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
expr_ref model::get_inlined_const_interp(func_decl* f) {
 | 
			
		||||
    expr* v = get_const_interp(f);
 | 
			
		||||
    if (!v) return expr_ref(0, m);
 | 
			
		||||
    top_sort st(m);
 | 
			
		||||
    expr_ref result1(v, m);
 | 
			
		||||
    expr_ref result2 = cleanup_expr(st, v, UINT_MAX);
 | 
			
		||||
    while (result1 != result2) {
 | 
			
		||||
        result1 = result2;
 | 
			
		||||
        result2 = cleanup_expr(st, result1, UINT_MAX);
 | 
			
		||||
    }
 | 
			
		||||
    return result2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref model::operator()(expr* t) {
 | 
			
		||||
    return m_mev(t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref_vector model::operator()(expr_ref_vector const& ts) {
 | 
			
		||||
    expr_ref_vector rs(m());
 | 
			
		||||
    expr_ref_vector rs(m);
 | 
			
		||||
    for (expr* t : ts) rs.push_back((*this)(t));
 | 
			
		||||
    return rs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool model::is_true(expr* t) {
 | 
			
		||||
    return m().is_true((*this)(t));
 | 
			
		||||
    return m.is_true((*this)(t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool model::is_false(expr* t) {
 | 
			
		||||
    return m().is_false((*this)(t));
 | 
			
		||||
    return m.is_false((*this)(t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool model::is_true(expr_ref_vector const& ts) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,12 +30,28 @@ typedef ref<model> model_ref;
 | 
			
		|||
class model : public model_core {
 | 
			
		||||
protected:
 | 
			
		||||
    typedef obj_map<sort, ptr_vector<expr>*> sort2universe;
 | 
			
		||||
    typedef obj_hashtable<func_decl> func_decl_set;
 | 
			
		||||
 | 
			
		||||
    ptr_vector<sort>              m_usorts;
 | 
			
		||||
    sort2universe                 m_usort2universe;
 | 
			
		||||
    model_evaluator               m_mev;
 | 
			
		||||
    bool                          m_cleaned;
 | 
			
		||||
    struct value_proc;
 | 
			
		||||
 | 
			
		||||
    struct deps_collector;    
 | 
			
		||||
    struct occs_collector;    
 | 
			
		||||
    struct top_sort;
 | 
			
		||||
 | 
			
		||||
    func_decl_set* collect_deps(top_sort& ts, expr * e);
 | 
			
		||||
    func_decl_set* collect_deps(top_sort& ts, func_interp* fi);
 | 
			
		||||
    void collect_deps(top_sort& ts);    
 | 
			
		||||
    void collect_occs(top_sort& ts, func_decl* f);
 | 
			
		||||
    void collect_occs(top_sort& ts, expr* e);
 | 
			
		||||
    void cleanup_interp(top_sort& ts, func_decl * f);
 | 
			
		||||
    expr_ref cleanup_expr(top_sort& ts, expr* e, unsigned current_partition);
 | 
			
		||||
    void remove_decls(ptr_vector<func_decl> & decls, func_decl_set const & s);
 | 
			
		||||
    bool can_inline_def(top_sort& ts, func_decl* f);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    model(ast_manager & m);
 | 
			
		||||
    ~model() override;
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +70,8 @@ public:
 | 
			
		|||
    sort * get_uninterpreted_sort(unsigned idx) const override;
 | 
			
		||||
    bool has_uninterpreted_sort(sort * s) const;
 | 
			
		||||
 | 
			
		||||
    expr_ref get_inlined_const_interp(func_decl* f);
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Primitives for building models
 | 
			
		||||
    //
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +81,8 @@ public:
 | 
			
		|||
    //
 | 
			
		||||
    model * translate(ast_translation & translator) const;
 | 
			
		||||
 | 
			
		||||
    void compress();
 | 
			
		||||
 | 
			
		||||
    void set_model_completion(bool f) { m_mev.set_model_completion(f); }
 | 
			
		||||
    void updt_params(params_ref const & p) { m_mev.updt_params(p); }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +114,5 @@ public:
 | 
			
		|||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::ostream& operator<<(std::ostream& out, model_core const& m);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* MODEL_H_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -147,7 +147,7 @@ void model2expr(model& md, expr_ref& result) {
 | 
			
		|||
        }
 | 
			
		||||
        if (f->get_arity() > 0) {
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(tmp, rev_vars.size(), rev_vars.c_ptr(), tmp);
 | 
			
		||||
            tmp = vs(tmp, rev_vars.size(), rev_vars.c_ptr());
 | 
			
		||||
            tmp = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp);
 | 
			
		||||
        }
 | 
			
		||||
        conjs.push_back(tmp);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,12 +20,12 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
model_core::~model_core() {
 | 
			
		||||
    for (auto & kv : m_interp) {
 | 
			
		||||
        m_manager.dec_ref(kv.m_key);
 | 
			
		||||
        m_manager.dec_ref(kv.m_value);
 | 
			
		||||
        m.dec_ref(kv.m_key);
 | 
			
		||||
        m.dec_ref(kv.m_value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (auto & kv : m_finterp) {
 | 
			
		||||
        m_manager.dec_ref(kv.m_key);
 | 
			
		||||
        m.dec_ref(kv.m_key);
 | 
			
		||||
        dealloc(kv.m_value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -47,32 +47,33 @@ bool model_core::eval(func_decl* f, expr_ref & r) const {
 | 
			
		|||
 | 
			
		||||
void model_core::register_decl(func_decl * d, expr * v) {
 | 
			
		||||
    SASSERT(d->get_arity() == 0);
 | 
			
		||||
    TRACE("model", tout << "register " << d->get_name() << "\n";);
 | 
			
		||||
    decl2expr::obj_map_entry * entry = m_interp.insert_if_not_there2(d, nullptr);
 | 
			
		||||
    if (entry->get_data().m_value == nullptr) {
 | 
			
		||||
        // new entry
 | 
			
		||||
        m_decls.push_back(d);
 | 
			
		||||
        m_const_decls.push_back(d);
 | 
			
		||||
        m_manager.inc_ref(d);
 | 
			
		||||
        m_manager.inc_ref(v);
 | 
			
		||||
        m.inc_ref(d);
 | 
			
		||||
        m.inc_ref(v);
 | 
			
		||||
        entry->get_data().m_value = v;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        // replacing entry
 | 
			
		||||
        m_manager.inc_ref(v);
 | 
			
		||||
        m_manager.dec_ref(entry->get_data().m_value);
 | 
			
		||||
        m.inc_ref(v);
 | 
			
		||||
        m.dec_ref(entry->get_data().m_value);
 | 
			
		||||
        entry->get_data().m_value = v;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void model_core::register_decl(func_decl * d, func_interp * fi) {
 | 
			
		||||
    SASSERT(d->get_arity() > 0);
 | 
			
		||||
    SASSERT(&fi->m() == &m_manager);
 | 
			
		||||
    SASSERT(&fi->m() == &m);
 | 
			
		||||
    decl2finterp::obj_map_entry * entry = m_finterp.insert_if_not_there2(d, nullptr);
 | 
			
		||||
    if (entry->get_data().m_value == nullptr) {
 | 
			
		||||
        // new entry
 | 
			
		||||
        m_decls.push_back(d);
 | 
			
		||||
        m_func_decls.push_back(d);
 | 
			
		||||
        m_manager.inc_ref(d);
 | 
			
		||||
        m.inc_ref(d);
 | 
			
		||||
        entry->get_data().m_value = fi;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
| 
						 | 
				
			
			@ -85,23 +86,23 @@ void model_core::register_decl(func_decl * d, func_interp * fi) {
 | 
			
		|||
 | 
			
		||||
void model_core::unregister_decl(func_decl * d) {
 | 
			
		||||
    decl2expr::obj_map_entry * ec = m_interp.find_core(d);
 | 
			
		||||
    if (ec && ec->get_data().m_value != 0) {
 | 
			
		||||
    if (ec) {
 | 
			
		||||
        auto k = ec->get_data().m_key;
 | 
			
		||||
        auto v = ec->get_data().m_value;
 | 
			
		||||
        m_interp.remove(d);
 | 
			
		||||
        m_const_decls.erase(d);
 | 
			
		||||
        m_manager.dec_ref(k);
 | 
			
		||||
        m_manager.dec_ref(v);
 | 
			
		||||
        m.dec_ref(k);
 | 
			
		||||
        m.dec_ref(v);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    decl2finterp::obj_map_entry * ef = m_finterp.find_core(d);
 | 
			
		||||
    if (ef && ef->get_data().m_value != 0) {
 | 
			
		||||
    if (ef) {
 | 
			
		||||
        auto k = ef->get_data().m_key;
 | 
			
		||||
        auto v = ef->get_data().m_value;
 | 
			
		||||
        m_finterp.remove(d);
 | 
			
		||||
        m_func_decls.erase(d);
 | 
			
		||||
        m_manager.dec_ref(k);
 | 
			
		||||
        m.dec_ref(k);
 | 
			
		||||
        dealloc(v);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ class model_core {
 | 
			
		|||
protected:
 | 
			
		||||
    typedef obj_map<func_decl, expr *>       decl2expr;
 | 
			
		||||
    typedef obj_map<func_decl, func_interp*> decl2finterp;
 | 
			
		||||
    ast_manager &                 m_manager;
 | 
			
		||||
    ast_manager &                 m;
 | 
			
		||||
    unsigned                      m_ref_count;
 | 
			
		||||
    decl2expr                     m_interp;      //!< interpretation for uninterpreted constants
 | 
			
		||||
    decl2finterp                  m_finterp;     //!< interpretation for uninterpreted functions
 | 
			
		||||
| 
						 | 
				
			
			@ -36,11 +36,10 @@ protected:
 | 
			
		|||
    ptr_vector<func_decl>         m_func_decls;  
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    model_core(ast_manager & m):m_manager(m), m_ref_count(0) { }
 | 
			
		||||
    model_core(ast_manager & m):m(m), m_ref_count(0) { }
 | 
			
		||||
    virtual ~model_core();
 | 
			
		||||
 | 
			
		||||
    ast_manager & get_manager() const { return m_manager; }
 | 
			
		||||
    ast_manager& m() const { return m_manager; }
 | 
			
		||||
    ast_manager & get_manager() const { return m; }
 | 
			
		||||
 | 
			
		||||
    unsigned get_num_decls() const { return m_decls.size(); }
 | 
			
		||||
    func_decl * get_decl(unsigned i) const { return m_decls[i]; }
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +64,11 @@ public:
 | 
			
		|||
 | 
			
		||||
    virtual expr * get_some_value(sort * s) = 0;
 | 
			
		||||
 | 
			
		||||
    expr * get_some_const_interp(func_decl * d) { 
 | 
			
		||||
        expr * r = get_const_interp(d); 
 | 
			
		||||
        if (r) return r; 
 | 
			
		||||
        return get_some_value(d->get_range()); 
 | 
			
		||||
    }
 | 
			
		||||
    //
 | 
			
		||||
    // Reference counting
 | 
			
		||||
    //
 | 
			
		||||
| 
						 | 
				
			
			@ -78,4 +82,7 @@ public:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::ostream& operator<<(std::ostream& out, model_core const& m);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,10 +16,12 @@ Author:
 | 
			
		|||
Revision History:
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "model/model.h"
 | 
			
		||||
#include "model/model_evaluator_params.hpp"
 | 
			
		||||
#include "ast/rewriter/rewriter_types.h"
 | 
			
		||||
#include "model/model_evaluator.h"
 | 
			
		||||
#include "model/model_v2_pp.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_types.h"
 | 
			
		||||
#include "ast/rewriter/bool_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/arith_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/bv_rewriter.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +31,6 @@ Revision History:
 | 
			
		|||
#include "ast/rewriter/array_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/fpa_rewriter.h"
 | 
			
		||||
#include "ast/rewriter/rewriter_def.h"
 | 
			
		||||
#include "util/cooperate.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "ast/ast_util.h"
 | 
			
		||||
#include "model/model_smt2_pp.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -274,7 +275,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
 | 
			
		|||
                fi->set_else(m.get_some_value(f->get_range()));
 | 
			
		||||
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(fi->get_interp(), num, args, result);
 | 
			
		||||
            result = vs(fi->get_interp(), num, args);
 | 
			
		||||
            return BR_REWRITE_FULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -304,6 +304,6 @@ void model_smt2_pp(std::ostream & out, ast_manager & m, model_core const & md, u
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
std::ostream& operator<<(std::ostream& out, model_core const& m) {
 | 
			
		||||
    model_smt2_pp(out, m.m(), m, 0);
 | 
			
		||||
    model_smt2_pp(out, m.get_manager(), m, 0);
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ expr_ref bind_variables::operator()(expr* fml, bool is_forall) {
 | 
			
		|||
    if (!m_names.empty()) {
 | 
			
		||||
        m_bound.reverse();
 | 
			
		||||
        m_names.reverse();
 | 
			
		||||
        result = m.mk_quantifier(is_forall, m_bound.size(), m_bound.c_ptr(), m_names.c_ptr(), result);
 | 
			
		||||
        result = m.mk_quantifier(is_forall ? forall_k : exists_k, m_bound.size(), m_bound.c_ptr(), m_names.c_ptr(), result);
 | 
			
		||||
    }
 | 
			
		||||
    m_pinned.reset();
 | 
			
		||||
    m_cache.reset();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1044,7 +1044,7 @@ namespace datalog {
 | 
			
		|||
                    quantifier* q = to_quantifier(body);
 | 
			
		||||
                    expr* e = q->get_expr();
 | 
			
		||||
                    if (m.is_implies(e, body, e2)) {
 | 
			
		||||
                        fml = m.mk_quantifier(false, q->get_num_decls(),
 | 
			
		||||
                        fml = m.mk_quantifier(exists_k, q->get_num_decls(),
 | 
			
		||||
                                              q->get_decl_sorts(), q->get_decl_names(),
 | 
			
		||||
                                              body);
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1251,13 +1251,10 @@ namespace datalog {
 | 
			
		|||
        obj_map<sort, unsigned> max_vars;
 | 
			
		||||
        for (unsigned i = 0; i < rules.size(); ++i) {
 | 
			
		||||
            expr* r = rules[i].get();
 | 
			
		||||
            if (!is_quantifier(r)) {
 | 
			
		||||
            if (!is_forall(r)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            quantifier* q = to_quantifier(r);
 | 
			
		||||
            if (!q->is_forall()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (has_quantifiers(q->get_expr())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1292,7 +1289,7 @@ namespace datalog {
 | 
			
		|||
                subst.push_back(fresh_vars[vars[max_var]].get());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            vsubst(q->get_expr(), subst.size(), subst.c_ptr(), res);
 | 
			
		||||
            res = vsubst(q->get_expr(), subst.size(), subst.c_ptr());
 | 
			
		||||
            rules[i] = res.get();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ namespace datalog {
 | 
			
		|||
                    args.push_back(m.mk_var(0, m.mk_bool_sort()));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            sub(q, args.size(), args.c_ptr(), q);
 | 
			
		||||
            q = sub(q, args.size(), args.c_ptr());
 | 
			
		||||
            vars.reset();
 | 
			
		||||
            m_free_vars(q);
 | 
			
		||||
            vars.append(m_free_vars.size(), m_free_vars.c_ptr());
 | 
			
		||||
| 
						 | 
				
			
			@ -438,11 +438,7 @@ namespace datalog {
 | 
			
		|||
                e = e2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (is_quantifier(e)) {
 | 
			
		||||
            q = to_quantifier(e);
 | 
			
		||||
            return q->is_forall();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
        return ::is_forall(e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -745,7 +741,7 @@ namespace datalog {
 | 
			
		|||
        expr_ref unbound_tail_pre_quant(m), fixed_tail(m), quant_tail(m);
 | 
			
		||||
 | 
			
		||||
        var_subst vs(m, false);
 | 
			
		||||
        vs(unbound_tail, subst.size(), subst.c_ptr(), unbound_tail_pre_quant);
 | 
			
		||||
        unbound_tail_pre_quant = vs(unbound_tail, subst.size(), subst.c_ptr());
 | 
			
		||||
 | 
			
		||||
        quant_tail = m.mk_exists(q_var_cnt, qsorts.c_ptr(), qnames.c_ptr(), unbound_tail_pre_quant);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -816,10 +812,10 @@ namespace datalog {
 | 
			
		|||
        app_ref_vector new_tail(m);
 | 
			
		||||
        svector<bool> tail_neg;
 | 
			
		||||
        var_subst vs(m, false);
 | 
			
		||||
        vs(r->get_head(), sz, es, tmp);
 | 
			
		||||
        tmp = vs(r->get_head(), sz, es);
 | 
			
		||||
        new_head = to_app(tmp);
 | 
			
		||||
        for (unsigned i = 0; i < r->get_tail_size(); ++i) {
 | 
			
		||||
            vs(r->get_tail(i), sz, es, tmp);
 | 
			
		||||
            tmp = vs(r->get_tail(i), sz, es);
 | 
			
		||||
            new_tail.push_back(to_app(tmp));
 | 
			
		||||
            tail_neg.push_back(r->is_neg_tail(i));
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -984,8 +980,7 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
        var_subst vs(m, false);
 | 
			
		||||
 | 
			
		||||
        expr_ref new_head_e(m);
 | 
			
		||||
        vs(m_head, subst_vals.size(), subst_vals.c_ptr(), new_head_e);
 | 
			
		||||
        expr_ref new_head_e = vs(m_head, subst_vals.size(), subst_vals.c_ptr());
 | 
			
		||||
 | 
			
		||||
        m.inc_ref(new_head_e);
 | 
			
		||||
        m.dec_ref(m_head);
 | 
			
		||||
| 
						 | 
				
			
			@ -993,8 +988,7 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
        for (unsigned i = 0; i < m_tail_size; i++) {
 | 
			
		||||
            app * old_tail = get_tail(i);
 | 
			
		||||
            expr_ref new_tail_e(m);
 | 
			
		||||
            vs(old_tail, subst_vals.size(), subst_vals.c_ptr(), new_tail_e);
 | 
			
		||||
            expr_ref new_tail_e = vs(old_tail, subst_vals.size(), subst_vals.c_ptr());
 | 
			
		||||
            bool  sign     = is_neg_tail(i);
 | 
			
		||||
            m.inc_ref(new_tail_e);
 | 
			
		||||
            m.dec_ref(old_tail);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,12 +82,10 @@ namespace datalog {
 | 
			
		|||
        quantifier_finder_proc() : m_exist(false), m_univ(false) {}
 | 
			
		||||
        void operator()(var * n) { }
 | 
			
		||||
        void operator()(quantifier * n) {
 | 
			
		||||
            if (n->is_forall()) {
 | 
			
		||||
                m_univ = true;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                SASSERT(n->is_exists());
 | 
			
		||||
                m_exist = true;
 | 
			
		||||
            switch (n->get_kind()) {
 | 
			
		||||
            case forall_k: m_univ = true; break;
 | 
			
		||||
            case exists_k: m_exist = true; break;
 | 
			
		||||
            case lambda_k: UNREACHABLE();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        void operator()(app * n) { }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,27 +31,20 @@ namespace datalog {
 | 
			
		|||
    rule_dependencies::rule_dependencies(const rule_dependencies & o, bool reversed):
 | 
			
		||||
        m_context(o.m_context) {
 | 
			
		||||
        if (reversed) {
 | 
			
		||||
            iterator oit = o.begin();
 | 
			
		||||
            iterator oend = o.end();
 | 
			
		||||
            for (; oit!=oend; ++oit) {
 | 
			
		||||
                func_decl * pred = oit->m_key;
 | 
			
		||||
                item_set & orig_items = *oit->get_value();
 | 
			
		||||
            for (auto & kv : o) { 
 | 
			
		||||
                func_decl * pred = kv.m_key;
 | 
			
		||||
                item_set & orig_items = *kv.get_value();
 | 
			
		||||
 | 
			
		||||
                ensure_key(pred);
 | 
			
		||||
                item_set::iterator dit = orig_items.begin();
 | 
			
		||||
                item_set::iterator dend = orig_items.end();
 | 
			
		||||
                for (; dit!=dend; ++dit) {
 | 
			
		||||
                    func_decl * master_pred = *dit;
 | 
			
		||||
                for (func_decl * master_pred : orig_items) {
 | 
			
		||||
                    insert(master_pred, pred);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            iterator oit = o.begin();
 | 
			
		||||
            iterator oend = o.end();
 | 
			
		||||
            for (; oit!=oend; ++oit) {
 | 
			
		||||
                func_decl * pred = oit->m_key;
 | 
			
		||||
                item_set & orig_items = *oit->get_value();
 | 
			
		||||
            for (auto & kv : o) {
 | 
			
		||||
                func_decl * pred = kv.m_key;
 | 
			
		||||
                item_set & orig_items = *kv.get_value();
 | 
			
		||||
                m_data.insert(pred, alloc(item_set, orig_items));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -86,14 +79,10 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
    void rule_dependencies::populate(const rule_set & rules) {
 | 
			
		||||
        SASSERT(m_data.empty());
 | 
			
		||||
        rule_set::decl2rules::iterator it  = rules.m_head2rules.begin();
 | 
			
		||||
        rule_set::decl2rules::iterator end = rules.m_head2rules.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            ptr_vector<rule> * rules = it->m_value;
 | 
			
		||||
            ptr_vector<rule>::iterator it2  = rules->begin();
 | 
			
		||||
            ptr_vector<rule>::iterator end2 = rules->end();
 | 
			
		||||
            for (; it2 != end2; ++it2) {
 | 
			
		||||
                populate(*it2);
 | 
			
		||||
        for (auto & kv : rules.m_head2rules) {
 | 
			
		||||
            ptr_vector<rule> * rules = kv.m_value;
 | 
			
		||||
            for (rule* r : *rules) {
 | 
			
		||||
                populate(r);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -150,54 +139,41 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
    void rule_dependencies::restrict(const item_set & allowed) {
 | 
			
		||||
        ptr_vector<func_decl> to_remove;
 | 
			
		||||
        iterator pit = begin();
 | 
			
		||||
        iterator pend = end();
 | 
			
		||||
        for (; pit!=pend; ++pit) {
 | 
			
		||||
            func_decl * pred = pit->m_key;
 | 
			
		||||
        for (auto const& kv : *this) {
 | 
			
		||||
            func_decl * pred = kv.m_key;
 | 
			
		||||
            if (!allowed.contains(pred)) {
 | 
			
		||||
                to_remove.insert(pred);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            item_set& itms = *pit->get_value();
 | 
			
		||||
            item_set& itms = *kv.get_value();
 | 
			
		||||
            set_intersection(itms, allowed);
 | 
			
		||||
        }
 | 
			
		||||
        ptr_vector<func_decl>::iterator rit = to_remove.begin();
 | 
			
		||||
        ptr_vector<func_decl>::iterator rend = to_remove.end();
 | 
			
		||||
        for (; rit != rend; ++rit) {
 | 
			
		||||
            remove_m_data_entry(*rit);
 | 
			
		||||
        }
 | 
			
		||||
        for (func_decl* f : to_remove) 
 | 
			
		||||
            remove_m_data_entry(f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void rule_dependencies::remove(func_decl * itm) {
 | 
			
		||||
        remove_m_data_entry(itm);
 | 
			
		||||
        iterator pit = begin();
 | 
			
		||||
        iterator pend = end();
 | 
			
		||||
        for (; pit != pend; ++pit) {
 | 
			
		||||
            item_set & itms = *pit->get_value();
 | 
			
		||||
        for (auto const& kv : *this) {
 | 
			
		||||
            item_set & itms = *kv.get_value();
 | 
			
		||||
            itms.remove(itm);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void rule_dependencies::remove(const item_set & to_remove) {
 | 
			
		||||
        item_set::iterator rit = to_remove.begin();
 | 
			
		||||
        item_set::iterator rend = to_remove.end();
 | 
			
		||||
        for (; rit!=rend; ++rit) {
 | 
			
		||||
            remove_m_data_entry(*rit);
 | 
			
		||||
        for (auto * item : to_remove) {
 | 
			
		||||
            remove_m_data_entry(item);
 | 
			
		||||
        }
 | 
			
		||||
        iterator pit = begin();
 | 
			
		||||
        iterator pend = end();
 | 
			
		||||
        for (; pit!=pend; ++pit) {
 | 
			
		||||
            item_set * itms = pit->get_value();
 | 
			
		||||
        for (auto & kv : *this) {
 | 
			
		||||
            item_set * itms = kv.get_value();
 | 
			
		||||
            set_difference(*itms, to_remove);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned rule_dependencies::out_degree(func_decl * f) const {
 | 
			
		||||
        unsigned res = 0;
 | 
			
		||||
        iterator pit = begin();
 | 
			
		||||
        iterator pend = end();
 | 
			
		||||
        for (; pit!=pend; ++pit) {
 | 
			
		||||
            item_set & itms = *pit->get_value();
 | 
			
		||||
        for (auto & kv : *this) {
 | 
			
		||||
            item_set & itms = *kv.get_value();
 | 
			
		||||
            if (itms.contains(f)) {
 | 
			
		||||
                res++;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -333,19 +309,11 @@ namespace datalog {
 | 
			
		|||
    void rule_set::inherit_predicates(rule_set const& other) {
 | 
			
		||||
        m_refs.append(other.m_refs);
 | 
			
		||||
        set_union(m_output_preds, other.m_output_preds);
 | 
			
		||||
        {
 | 
			
		||||
            obj_map<func_decl, func_decl*>::iterator it = other.m_orig2pred.begin();
 | 
			
		||||
            obj_map<func_decl, func_decl*>::iterator end = other.m_orig2pred.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                m_orig2pred.insert(it->m_key, it->m_value);
 | 
			
		||||
            }
 | 
			
		||||
        for (auto & kv : other.m_orig2pred) {
 | 
			
		||||
            m_orig2pred.insert(kv.m_key, kv.m_value);
 | 
			
		||||
        }
 | 
			
		||||
        {
 | 
			
		||||
            obj_map<func_decl, func_decl*>::iterator it = other.m_pred2orig.begin();
 | 
			
		||||
            obj_map<func_decl, func_decl*>::iterator end = other.m_pred2orig.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                m_pred2orig.insert(it->m_key, it->m_value);
 | 
			
		||||
            }
 | 
			
		||||
        for (auto & kv : other.m_pred2orig) {
 | 
			
		||||
            m_pred2orig.insert(kv.m_key, kv.m_value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -537,26 +505,19 @@ namespace datalog {
 | 
			
		|||
    void rule_set::display_deps( std::ostream & out ) const
 | 
			
		||||
    {
 | 
			
		||||
        const pred_set_vector & strats = get_strats();
 | 
			
		||||
        pred_set_vector::const_iterator sit = strats.begin();
 | 
			
		||||
        pred_set_vector::const_iterator send = strats.end();
 | 
			
		||||
        for (; sit!=send; ++sit) {
 | 
			
		||||
            func_decl_set & strat = **sit;
 | 
			
		||||
            func_decl_set::iterator fit=strat.begin();
 | 
			
		||||
            func_decl_set::iterator fend=strat.end();
 | 
			
		||||
            bool non_empty = false;
 | 
			
		||||
            for (; fit!=fend; ++fit) {
 | 
			
		||||
                func_decl * first = *fit;
 | 
			
		||||
                const func_decl_set & deps = m_deps.get_deps(first);
 | 
			
		||||
                func_decl_set::iterator dit=deps.begin();
 | 
			
		||||
                func_decl_set::iterator dend=deps.end();
 | 
			
		||||
                for (; dit!=dend; ++dit) {
 | 
			
		||||
                    non_empty = true;
 | 
			
		||||
                    func_decl * dep = *dit;
 | 
			
		||||
                    out<<first->get_name()<<" -> "<<dep->get_name()<<"\n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (non_empty && sit!=send) {
 | 
			
		||||
        bool non_empty = false;
 | 
			
		||||
        for (func_decl_set* strat : strats) {
 | 
			
		||||
            if (non_empty) {
 | 
			
		||||
                out << "\n";
 | 
			
		||||
                non_empty = false;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            for (func_decl * first : *strat) {
 | 
			
		||||
                const func_decl_set & deps = m_deps.get_deps(first);
 | 
			
		||||
                for (func_decl * dep : deps) {
 | 
			
		||||
                    non_empty = true;
 | 
			
		||||
                    out<<first->get_name()<<" -> " <<dep->get_name()<<"\n";
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -568,11 +529,8 @@ namespace datalog {
 | 
			
		|||
    // -----------------------------------
 | 
			
		||||
 | 
			
		||||
    rule_stratifier::~rule_stratifier() {
 | 
			
		||||
        comp_vector::iterator it = m_strats.begin();
 | 
			
		||||
        comp_vector::iterator end = m_strats.end();
 | 
			
		||||
        for (; it!=end; ++it) {
 | 
			
		||||
            SASSERT(*it);
 | 
			
		||||
            dealloc(*it);
 | 
			
		||||
        for (auto * t : m_strats) {
 | 
			
		||||
            dealloc(t);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -617,10 +575,8 @@ namespace datalog {
 | 
			
		|||
            m_stack_P.push_back(el);
 | 
			
		||||
 | 
			
		||||
            const item_set & children = m_deps.get_deps(el);
 | 
			
		||||
            item_set::iterator cit=children.begin();
 | 
			
		||||
            item_set::iterator cend=children.end();
 | 
			
		||||
            for (; cit!=cend; ++cit) {
 | 
			
		||||
                traverse(*cit);
 | 
			
		||||
            for (T* ch : children) {
 | 
			
		||||
                traverse(ch);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (el == m_stack_P.back()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -646,10 +602,8 @@ namespace datalog {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        //detect strong components
 | 
			
		||||
        rule_dependencies::iterator it = m_deps.begin();
 | 
			
		||||
        rule_dependencies::iterator end = m_deps.end();
 | 
			
		||||
        for (; it!=end; ++it) {
 | 
			
		||||
            T * el = it->m_key;
 | 
			
		||||
        for (auto const& kv : m_deps) {
 | 
			
		||||
            T * el = kv.m_key;
 | 
			
		||||
            //we take a note of the preorder number with which this sweep started
 | 
			
		||||
            m_first_preorder = m_next_preorder;
 | 
			
		||||
            traverse(el);
 | 
			
		||||
| 
						 | 
				
			
			@ -662,19 +616,13 @@ namespace datalog {
 | 
			
		|||
        in_degrees.resize(m_components.size());
 | 
			
		||||
 | 
			
		||||
        //init in_degrees
 | 
			
		||||
        it = m_deps.begin();
 | 
			
		||||
        end = m_deps.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            T * el = it->m_key;
 | 
			
		||||
            item_set * out_edges = it->m_value;
 | 
			
		||||
        for (auto const& kv : m_deps) {
 | 
			
		||||
            T * el = kv.m_key;
 | 
			
		||||
            item_set * out_edges = kv.m_value;
 | 
			
		||||
 | 
			
		||||
            unsigned el_comp = 0;
 | 
			
		||||
            VERIFY( m_component_nums.find(el, el_comp) );
 | 
			
		||||
            unsigned el_comp = m_component_nums[el];
 | 
			
		||||
 | 
			
		||||
            item_set::iterator eit = out_edges->begin();
 | 
			
		||||
            item_set::iterator eend = out_edges->end();
 | 
			
		||||
            for (; eit!=eend; ++eit) {
 | 
			
		||||
                T * tgt = *eit;
 | 
			
		||||
            for (T * tgt : *out_edges) {
 | 
			
		||||
 | 
			
		||||
                unsigned tgt_comp = m_component_nums.find(tgt);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -701,15 +649,9 @@ namespace datalog {
 | 
			
		|||
        unsigned strats_index = 0;
 | 
			
		||||
        while (strats_index < m_strats.size()) { //m_strats.size() changes inside the loop!
 | 
			
		||||
            item_set * comp = m_strats[strats_index];
 | 
			
		||||
            item_set::iterator cit=comp->begin();
 | 
			
		||||
            item_set::iterator cend=comp->end();
 | 
			
		||||
            for (; cit!=cend; ++cit) {
 | 
			
		||||
                T * el = *cit;
 | 
			
		||||
            for (T * el : *comp) {
 | 
			
		||||
                const item_set & deps = m_deps.get_deps(el);
 | 
			
		||||
                item_set::iterator eit=deps.begin();
 | 
			
		||||
                item_set::iterator eend=deps.end();
 | 
			
		||||
                for (; eit!=eend; ++eit) {
 | 
			
		||||
                    T * tgt = *eit;
 | 
			
		||||
                for (T * tgt : deps) {
 | 
			
		||||
                    unsigned tgt_comp = 0;
 | 
			
		||||
                    VERIFY( m_component_nums.find(tgt, tgt_comp) );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -724,7 +666,7 @@ namespace datalog {
 | 
			
		|||
                            m_components[tgt_comp] = 0;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    traverse(*cit);
 | 
			
		||||
                    traverse(el);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            strats_index++;
 | 
			
		||||
| 
						 | 
				
			
			@ -738,12 +680,9 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
        SASSERT(m_pred_strat_nums.empty());
 | 
			
		||||
        unsigned strat_cnt = m_strats.size();
 | 
			
		||||
        for (unsigned strat_index=0; strat_index<strat_cnt; strat_index++) {
 | 
			
		||||
        for (unsigned strat_index=0; strat_index < strat_cnt; strat_index++) {
 | 
			
		||||
            item_set * comp = m_strats[strat_index];
 | 
			
		||||
            item_set::iterator cit=comp->begin();
 | 
			
		||||
            item_set::iterator cend=comp->end();
 | 
			
		||||
            for (; cit != cend; ++cit) {
 | 
			
		||||
                T * el = *cit;
 | 
			
		||||
            for (T * el : *comp) {
 | 
			
		||||
                m_pred_strat_nums.insert(el, strat_index);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -761,10 +700,8 @@ namespace datalog {
 | 
			
		|||
        m_deps.display(out << "dependencies\n");
 | 
			
		||||
        out << "strata\n";
 | 
			
		||||
        for (unsigned i = 0; i < m_strats.size(); ++i) {
 | 
			
		||||
            item_set::iterator it  = m_strats[i]->begin();
 | 
			
		||||
            item_set::iterator end = m_strats[i]->end();            
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                out << (*it)->get_name() << " ";
 | 
			
		||||
            for (auto * item : *m_strats[i]) {
 | 
			
		||||
                out << item->get_name() << " ";
 | 
			
		||||
            }
 | 
			
		||||
            out << "\n";
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,8 +115,7 @@ namespace datalog {
 | 
			
		|||
        expr_ref tmp(m);
 | 
			
		||||
        for (unsigned i = 0; i < tgt.size(); ++i) {
 | 
			
		||||
            if (tgt[i].get()) {
 | 
			
		||||
                vs(tgt[i].get(), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                tgt[i] = tmp;
 | 
			
		||||
                tgt[i] = vs(tgt[i].get(), sub.size(), sub.c_ptr());
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                tgt[i] = sub[i];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -108,20 +108,20 @@ namespace datalog {
 | 
			
		|||
                    // apply substitution to body.
 | 
			
		||||
                    var_subst vs(m, false);
 | 
			
		||||
                    for (unsigned k = 0; k < p->get_arity(); ++k) {
 | 
			
		||||
                        vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), trm);
 | 
			
		||||
                        trm = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                        conjs.push_back(m.mk_eq(trm, mk_q_arg(p, k, true)));
 | 
			
		||||
                    }
 | 
			
		||||
                    for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
 | 
			
		||||
                        func_decl* q = r.get_decl(j);
 | 
			
		||||
                        for (unsigned k = 0; k < q->get_arity(); ++k) {
 | 
			
		||||
                            vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), trm);
 | 
			
		||||
                            trm = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                            conjs.push_back(m.mk_eq(trm, mk_q_arg(q, k, false)));
 | 
			
		||||
                        }
 | 
			
		||||
                        func_decl_ref qr = mk_q_func_decl(q);
 | 
			
		||||
                        conjs.push_back(m.mk_app(qr, m_bv.mk_bv_sub(var, mk_q_one())));
 | 
			
		||||
                    }
 | 
			
		||||
                    for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
 | 
			
		||||
                        vs(r.get_tail(j), sub.size(), sub.c_ptr(), trm);
 | 
			
		||||
                        trm = vs(r.get_tail(j), sub.size(), sub.c_ptr());
 | 
			
		||||
                        conjs.push_back(trm);
 | 
			
		||||
                    }
 | 
			
		||||
                    if (r.get_uninterpreted_tail_size() > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -238,7 +238,7 @@ namespace datalog {
 | 
			
		|||
            var_subst vs(m, false);
 | 
			
		||||
            num = mk_q_num(i);
 | 
			
		||||
            expr* nums[1] = { num };
 | 
			
		||||
            vs(t, 1, nums, tmp);
 | 
			
		||||
            tmp = vs(t, 1, nums);
 | 
			
		||||
            return (*model)(tmp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -535,7 +535,7 @@ namespace datalog {
 | 
			
		|||
            for (unsigned j = 0; j < sz; ++j) {
 | 
			
		||||
                func_decl* head_j = r->get_decl(j);
 | 
			
		||||
                app* body_j = r->get_tail(j);
 | 
			
		||||
                vs(body_j, sub.size(), sub.c_ptr(), prop_body);
 | 
			
		||||
                prop_body = vs(body_j, sub.size(), sub.c_ptr());
 | 
			
		||||
                prs.push_back(get_proof(md, head_j, to_app(prop_body), level-1));
 | 
			
		||||
                positions.push_back(std::make_pair(j+1,0));
 | 
			
		||||
                substs.push_back(expr_ref_vector(m));
 | 
			
		||||
| 
						 | 
				
			
			@ -609,11 +609,9 @@ namespace datalog {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        expr_ref skolemize_vars(rule& r, expr_ref_vector const& args, ptr_vector<sort> const& vars, expr* e) {
 | 
			
		||||
            expr_ref        result(m);
 | 
			
		||||
            expr_ref_vector binding = mk_skolem_binding(r, vars, args);
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(e, binding.size(), binding.c_ptr(), result);
 | 
			
		||||
            return result;
 | 
			
		||||
            return vs(e, binding.size(), binding.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        func_decl_ref mk_body_func(rule& r, ptr_vector<sort> const& args, unsigned index, sort* s) {
 | 
			
		||||
| 
						 | 
				
			
			@ -646,8 +644,8 @@ namespace datalog {
 | 
			
		|||
                return expr_ref(e, m);
 | 
			
		||||
            }
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(e, binding.size(), binding.c_ptr(), tmp);
 | 
			
		||||
            vs(pat, binding.size(), binding.c_ptr(), head);
 | 
			
		||||
            tmp = vs(e, binding.size(), binding.c_ptr());
 | 
			
		||||
            head = vs(pat, binding.size(), binding.c_ptr());
 | 
			
		||||
            patterns.push_back(m.mk_pattern(to_app(head)));
 | 
			
		||||
            symbol qid, skid;
 | 
			
		||||
            return expr_ref(m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), tmp, 1, qid, skid, 1, patterns.c_ptr()), m);
 | 
			
		||||
| 
						 | 
				
			
			@ -892,7 +890,7 @@ namespace datalog {
 | 
			
		|||
                    // apply substitution to body.
 | 
			
		||||
                    var_subst vs(m, false);
 | 
			
		||||
                    for (unsigned k = 0; k < p->get_arity(); ++k) {
 | 
			
		||||
                        vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                        tmp = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                        expr_ref arg = mk_arg(p, k, path_var, trace_arg);
 | 
			
		||||
                        conjs.push_back(m.mk_eq(tmp, arg));
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			@ -906,7 +904,7 @@ namespace datalog {
 | 
			
		|||
                        }
 | 
			
		||||
                        func_decl* q = r.get_decl(j);
 | 
			
		||||
                        for (unsigned k = 0; k < q->get_arity(); ++k) {
 | 
			
		||||
                            vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                            tmp = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                            expr_ref arg = mk_arg(q, k, path_arg, vars[j].get());
 | 
			
		||||
                            conjs.push_back(m.mk_eq(tmp, arg));
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -914,7 +912,7 @@ namespace datalog {
 | 
			
		|||
                        conjs.push_back(m.mk_app(q_pred, vars[j].get(), path_arg));
 | 
			
		||||
                    }
 | 
			
		||||
                    for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
 | 
			
		||||
                        vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                        tmp = vs(r.get_tail(j), sub.size(), sub.c_ptr());
 | 
			
		||||
                        conjs.push_back(tmp);
 | 
			
		||||
                    }
 | 
			
		||||
                    bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,7 +1046,7 @@ namespace datalog {
 | 
			
		|||
                    expr_ref fml(m), head(m), tmp(m);
 | 
			
		||||
                    app_ref path1(m);
 | 
			
		||||
 | 
			
		||||
                    var_subst vs(m, false);
 | 
			
		||||
                    // var_subst vs(m, false);
 | 
			
		||||
                    mk_subst(*rules[i], path, trace, sub);
 | 
			
		||||
                    rm.to_formula(*rules[i], fml);
 | 
			
		||||
                    prs.push_back(rules[i]->get_proof());
 | 
			
		||||
| 
						 | 
				
			
			@ -1399,20 +1397,20 @@ namespace datalog {
 | 
			
		|||
                    // apply substitution to body.
 | 
			
		||||
                    var_subst vs(m, false);
 | 
			
		||||
                    for (unsigned k = 0; k < p->get_arity(); ++k) {
 | 
			
		||||
                        vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                        tmp = vs(r.get_head()->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                        conjs.push_back(m.mk_eq(tmp, mk_level_arg(p, k, level)));
 | 
			
		||||
                    }
 | 
			
		||||
                    for (unsigned j = 0; j < r.get_uninterpreted_tail_size(); ++j) {
 | 
			
		||||
                        SASSERT(level > 0);
 | 
			
		||||
                        func_decl* q = r.get_decl(j);
 | 
			
		||||
                        for (unsigned k = 0; k < q->get_arity(); ++k) {
 | 
			
		||||
                            vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                            tmp = vs(r.get_tail(j)->get_arg(k), sub.size(), sub.c_ptr());
 | 
			
		||||
                            conjs.push_back(m.mk_eq(tmp, mk_level_arg(q, k, level-1)));
 | 
			
		||||
                        }
 | 
			
		||||
                        conjs.push_back(mk_level_predicate(q, level-1));
 | 
			
		||||
                    }
 | 
			
		||||
                    for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) {
 | 
			
		||||
                        vs(r.get_tail(j), sub.size(), sub.c_ptr(), tmp);
 | 
			
		||||
                        tmp = vs(r.get_tail(j), sub.size(), sub.c_ptr());
 | 
			
		||||
                        conjs.push_back(tmp);
 | 
			
		||||
                    }
 | 
			
		||||
                    bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), rule_body);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,7 +121,7 @@ namespace datalog {
 | 
			
		|||
                    m_ground[i] = m.mk_fresh_const("c", fv[i]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e);
 | 
			
		||||
            e = m_var_subst(e, m_ground.size(), m_ground.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static bool rule_sort_fn(const rule *r1, const rule *r2) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,9 +59,7 @@ namespace datalog {
 | 
			
		|||
        for (unsigned i = 0; i < sig.size(); ++i) {
 | 
			
		||||
            vars.push_back(m.mk_const(symbol(i), sig[i]));
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref result(m);
 | 
			
		||||
        sub(fml, vars.size(), vars.c_ptr(), result);
 | 
			
		||||
        return result;
 | 
			
		||||
        return sub(fml, vars.size(), vars.c_ptr());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void check_relation::add_fact(const relation_fact & f) {
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +290,7 @@ namespace datalog {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
        var_subst sub(m, false);
 | 
			
		||||
        sub(fml, vars.size(), vars.c_ptr(), fml1);
 | 
			
		||||
        fml1 = sub(fml, vars.size(), vars.c_ptr());
 | 
			
		||||
        bound.reverse();        
 | 
			
		||||
        fml1 = m.mk_exists(bound.size(), bound.c_ptr(), names.c_ptr(), fml1);
 | 
			
		||||
        return fml1;        
 | 
			
		||||
| 
						 | 
				
			
			@ -333,7 +331,7 @@ namespace datalog {
 | 
			
		|||
        for (unsigned i = 0; i < sig2.size(); ++i) {
 | 
			
		||||
            vars.push_back(m.mk_var(i + sig1.size(), sig2[i]));
 | 
			
		||||
        }
 | 
			
		||||
        sub(fml2, vars.size(), vars.c_ptr(), fml2);
 | 
			
		||||
        fml2 = sub(fml2, vars.size(), vars.c_ptr());
 | 
			
		||||
        fml1 = m.mk_and(fml1, fml2);
 | 
			
		||||
        for (unsigned i = 0; i < cols1.size(); ++i) {
 | 
			
		||||
            unsigned v1 = cols1[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -372,14 +370,14 @@ namespace datalog {
 | 
			
		|||
        expr_ref fml1(m), fml2(m);
 | 
			
		||||
        src.to_formula(fml1);
 | 
			
		||||
        dst.to_formula(fml2);
 | 
			
		||||
        subst(fml1, sub.size(), sub.c_ptr(), fml1);
 | 
			
		||||
        fml1 = subst(fml1, sub.size(), sub.c_ptr());
 | 
			
		||||
        expr_ref_vector vars(m);
 | 
			
		||||
        for (unsigned i = 0; i < sig2.size(); ++i) {
 | 
			
		||||
            vars.push_back(m.mk_const(symbol(i), sig2[i]));            
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        subst(fml1, vars.size(), vars.c_ptr(), fml1);
 | 
			
		||||
        subst(fml2, vars.size(), vars.c_ptr(), fml2);
 | 
			
		||||
        fml1 = subst(fml1, vars.size(), vars.c_ptr());
 | 
			
		||||
        fml2 = subst(fml2, vars.size(), vars.c_ptr());
 | 
			
		||||
        
 | 
			
		||||
        check_equiv("permutation", fml1, fml2);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -405,8 +403,8 @@ namespace datalog {
 | 
			
		|||
            strm << "x" << i;
 | 
			
		||||
            vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i]));            
 | 
			
		||||
        }
 | 
			
		||||
        sub(fml1, vars.size(), vars.c_ptr(), fml1);
 | 
			
		||||
        sub(fml2, vars.size(), vars.c_ptr(), fml2);
 | 
			
		||||
        fml1 = sub(fml1, vars.size(), vars.c_ptr());
 | 
			
		||||
        fml2 = sub(fml2, vars.size(), vars.c_ptr());
 | 
			
		||||
        check_equiv("filter", fml1, fml2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -453,8 +451,8 @@ namespace datalog {
 | 
			
		|||
            strm << "x" << i;
 | 
			
		||||
            vars.push_back(m.mk_const(symbol(strm.str().c_str()), sig[i]));            
 | 
			
		||||
        }
 | 
			
		||||
        sub(fml1, vars.size(), vars.c_ptr(), fml1);
 | 
			
		||||
        sub(fml2, vars.size(), vars.c_ptr(), fml2);
 | 
			
		||||
        fml1 = sub(fml1, vars.size(), vars.c_ptr());
 | 
			
		||||
        fml2 = sub(fml2, vars.size(), vars.c_ptr());
 | 
			
		||||
 | 
			
		||||
        check_equiv("union", fml1, fml2);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -466,13 +464,13 @@ namespace datalog {
 | 
			
		|||
            // dst \ dst0 == delta & dst & \ dst0
 | 
			
		||||
            expr_ref fml4(m), fml5(m);
 | 
			
		||||
            fml4 = m.mk_and(fml2, m.mk_not(dst0));
 | 
			
		||||
            sub(fml4, vars.size(), vars.c_ptr(), fml4);
 | 
			
		||||
            sub(d, vars.size(), vars.c_ptr(), d);
 | 
			
		||||
            fml4 = sub(fml4, vars.size(), vars.c_ptr());
 | 
			
		||||
            d = sub(d, vars.size(), vars.c_ptr());
 | 
			
		||||
            check_contains("union_delta low", d, fml4);
 | 
			
		||||
            //
 | 
			
		||||
            // delta >= delta0 
 | 
			
		||||
            //
 | 
			
		||||
            sub(delta0, vars.size(), vars.c_ptr(), d0);
 | 
			
		||||
            d0 = sub(delta0, vars.size(), vars.c_ptr());
 | 
			
		||||
            check_contains("union delta0", d, d0);
 | 
			
		||||
 | 
			
		||||
            //
 | 
			
		||||
| 
						 | 
				
			
			@ -480,8 +478,8 @@ namespace datalog {
 | 
			
		|||
            //
 | 
			
		||||
            fml4 = m.mk_or(fml2, delta0);
 | 
			
		||||
            fml5 = m.mk_or(d, dst0);
 | 
			
		||||
            sub(fml4, vars.size(), vars.c_ptr(), fml4);
 | 
			
		||||
            sub(fml5, vars.size(), vars.c_ptr(), fml5);
 | 
			
		||||
            fml4 = sub(fml4, vars.size(), vars.c_ptr());
 | 
			
		||||
            fml5 = sub(fml5, vars.size(), vars.c_ptr());
 | 
			
		||||
            check_equiv("union no overflow", fml4, fml5);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -725,8 +725,7 @@ namespace datalog {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            expr_ref renamed(m);
 | 
			
		||||
            m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr(), renamed);
 | 
			
		||||
            expr_ref renamed = m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr());
 | 
			
		||||
            app_ref app_renamed(to_app(renamed), m);
 | 
			
		||||
            if (remove_columns.empty()) {
 | 
			
		||||
                if (!dealloc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1311,8 +1311,7 @@ namespace datalog {
 | 
			
		|||
            if(m_rel_cond_columns.empty()) {
 | 
			
		||||
                expr_ref_vector renaming(m_manager);
 | 
			
		||||
                get_renaming_args(r.m_sig2table, r.get_signature(), renaming);
 | 
			
		||||
                expr_ref table_cond(m_manager);
 | 
			
		||||
                m_subst(condition, renaming.size(), renaming.c_ptr(), table_cond);
 | 
			
		||||
                expr_ref table_cond = m_subst(condition, renaming.size(), renaming.c_ptr());
 | 
			
		||||
                m_table_filter = rmgr.mk_filter_interpreted_fn(r.get_table(), to_app(table_cond));
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1361,9 +1360,7 @@ namespace datalog {
 | 
			
		|||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    if(!m_rel_filter) {
 | 
			
		||||
                        expr_ref inner_cond(m_manager);
 | 
			
		||||
                        m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr(), 
 | 
			
		||||
                            inner_cond);
 | 
			
		||||
                        expr_ref inner_cond = m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr());
 | 
			
		||||
                        m_rel_filter = rmgr.mk_filter_interpreted_fn(*inner, to_app(inner_cond));
 | 
			
		||||
                    }
 | 
			
		||||
                    (*m_rel_filter)(*inner);
 | 
			
		||||
| 
						 | 
				
			
			@ -1411,8 +1408,7 @@ namespace datalog {
 | 
			
		|||
 | 
			
		||||
                //create the condition with table values substituted in and relation values properly renamed
 | 
			
		||||
                expr_ref inner_cond(m_manager);
 | 
			
		||||
                m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr(), 
 | 
			
		||||
                    inner_cond);
 | 
			
		||||
                inner_cond = m_subst(m_cond, m_renaming_for_inner_rel.size(), m_renaming_for_inner_rel.c_ptr());
 | 
			
		||||
 | 
			
		||||
                relation_base * new_rel = old_rel.clone();
 | 
			
		||||
                
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -471,8 +471,7 @@ namespace datalog {
 | 
			
		|||
                SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, i));
 | 
			
		||||
                subst_arg[ofs-i] = r.m_data.get(i);
 | 
			
		||||
            }
 | 
			
		||||
            expr_ref res(m_manager);
 | 
			
		||||
            m_subst(m_new_rule, subst_arg.size(), subst_arg.c_ptr(), res);
 | 
			
		||||
            expr_ref res = m_subst(m_new_rule, subst_arg.size(), subst_arg.c_ptr());
 | 
			
		||||
            r.m_data[m_col_idx] = to_app(res);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -246,8 +246,8 @@ namespace datalog {
 | 
			
		|||
            get_normalizer(t1, t2, norm_subst);
 | 
			
		||||
            expr_ref t1n_ref(m);
 | 
			
		||||
            expr_ref t2n_ref(m);
 | 
			
		||||
            m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr(), t1n_ref);
 | 
			
		||||
            m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref);
 | 
			
		||||
            t1n_ref = m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr());
 | 
			
		||||
            t2n_ref = m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr());
 | 
			
		||||
            app * t1n = to_app(t1n_ref);
 | 
			
		||||
            app * t2n = to_app(t2n_ref);
 | 
			
		||||
            if (t1n->get_id() > t2n->get_id()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -531,7 +531,7 @@ namespace datalog {
 | 
			
		|||
                    expr_ref_vector denormalizer(m);
 | 
			
		||||
                    reverse_renaming(m, normalizer, denormalizer);
 | 
			
		||||
                    expr_ref new_transf(m);
 | 
			
		||||
                    m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr(), new_transf);
 | 
			
		||||
                    new_transf = m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr());
 | 
			
		||||
                    app * new_lit = to_app(new_transf);
 | 
			
		||||
 | 
			
		||||
                    m_pinned.push_back(new_lit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1395,8 +1395,7 @@ namespace datalog {
 | 
			
		|||
                args.push_back(m_decl_util.mk_numeral(el, m_free_vars[i]));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            expr_ref ground(m_ast_manager);
 | 
			
		||||
            m_vs(m_condition.get(), args.size(), args.c_ptr(), ground);
 | 
			
		||||
            expr_ref ground = m_vs(m_condition.get(), args.size(), args.c_ptr());
 | 
			
		||||
            m_simp(ground);
 | 
			
		||||
 | 
			
		||||
            return m_ast_manager.is_false(ground);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ namespace datalog {
 | 
			
		|||
            s.push_back(m.mk_var(idx, sig[i]));
 | 
			
		||||
        }
 | 
			
		||||
        get_inner().to_formula(tmp);
 | 
			
		||||
        get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr(), fml);
 | 
			
		||||
        fml = get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -584,8 +584,7 @@ namespace datalog {
 | 
			
		|||
            }
 | 
			
		||||
            subst_vect[subst_ofs-i] = m.mk_var(r.m_sig2inner[i], sig[i]);
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref inner_cond(m);
 | 
			
		||||
        get_context().get_var_subst()(condition, subst_vect.size(), subst_vect.c_ptr(), inner_cond);
 | 
			
		||||
        expr_ref inner_cond = get_context().get_var_subst()(condition, subst_vect.size(), subst_vect.c_ptr());
 | 
			
		||||
 | 
			
		||||
        relation_mutator_fn * inner_fun = get_manager().mk_filter_interpreted_fn(r.get_inner(), to_app(inner_cond));
 | 
			
		||||
        if(!inner_fun) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -526,7 +526,7 @@ void lemma::mk_expr_core() {
 | 
			
		|||
                sorts.push_back(get_sort(zks.get(i)));
 | 
			
		||||
                names.push_back(zks.get(i)->get_decl()->get_name());
 | 
			
		||||
            }
 | 
			
		||||
            m_body = m.mk_quantifier(true, zks.size(),
 | 
			
		||||
            m_body = m.mk_quantifier(forall_k, zks.size(),
 | 
			
		||||
                                     sorts.c_ptr(),
 | 
			
		||||
                                     names.c_ptr(),
 | 
			
		||||
                                     m_body, 15, symbol(m_body->get_id()));
 | 
			
		||||
| 
						 | 
				
			
			@ -633,7 +633,7 @@ void lemma::instantiate(expr * const * exprs, expr_ref &result, expr *e) {
 | 
			
		|||
    expr *body = to_quantifier(lem)->get_expr();
 | 
			
		||||
    unsigned num_decls = to_quantifier(lem)->get_num_decls();
 | 
			
		||||
    var_subst vs(m, false);
 | 
			
		||||
    vs(body, num_decls, exprs, result);
 | 
			
		||||
    result = vs(body, num_decls, exprs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lemma::set_level (unsigned lvl) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1347,7 +1347,7 @@ lbool pred_transformer::is_reachable(pob& n, expr_ref_vector* core,
 | 
			
		|||
 | 
			
		||||
    if (is_sat == l_true || is_sat == l_undef) {
 | 
			
		||||
        if (core) { core->reset(); }
 | 
			
		||||
        if (model && model->get()) {
 | 
			
		||||
        if (model) {
 | 
			
		||||
            r = find_rule(**model, is_concrete, reach_pred_used, num_reuse_reach);
 | 
			
		||||
            TRACE ("spacer", tout << "reachable "
 | 
			
		||||
                   << "is_concrete " << is_concrete << " rused: ";
 | 
			
		||||
| 
						 | 
				
			
			@ -1621,9 +1621,7 @@ void pred_transformer::init_rule(decl2rel const& pts, datalog::rule const& rule)
 | 
			
		|||
        ground_free_vars(trans, var_reprs, aux_vars, ut_size == 0);
 | 
			
		||||
        SASSERT(is_all_non_null(var_reprs));
 | 
			
		||||
 | 
			
		||||
        expr_ref tmp(m);
 | 
			
		||||
        var_subst(m, false)(trans, var_reprs.size (),
 | 
			
		||||
                            (expr*const*)var_reprs.c_ptr(), tmp);
 | 
			
		||||
        expr_ref tmp = var_subst(m, false)(trans, var_reprs.size (), (expr*const*)var_reprs.c_ptr());
 | 
			
		||||
        flatten_and (tmp, side);
 | 
			
		||||
        trans = mk_and(side);
 | 
			
		||||
        side.reset ();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ public:
 | 
			
		|||
    bool is_h_marked(proof* p) {return m_h_mark.is_marked(p);}
 | 
			
		||||
 | 
			
		||||
    bool is_b_pure (proof *p) {
 | 
			
		||||
        return !is_h_marked(p) && !this->is_a_marked(p) && is_core_pure(m.get_fact(p));
 | 
			
		||||
        return !is_h_marked (p) && !this->is_a_marked(p) && is_core_pure(m.get_fact (p));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void display_dot(std::ostream &out);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -322,24 +322,6 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
 | 
			
		|||
        // -- new hypothesis reducer
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
#if 0
 | 
			
		||||
            static unsigned bcnt = 0;
 | 
			
		||||
            {
 | 
			
		||||
                bcnt++;
 | 
			
		||||
                TRACE("spacer", tout << "Dumping pf bcnt: " << bcnt << "\n";);
 | 
			
		||||
                if (bcnt == 123) {
 | 
			
		||||
                    std::ofstream ofs;
 | 
			
		||||
                    ofs.open("/tmp/bpf_" + std::to_string(bcnt) + ".dot");
 | 
			
		||||
                    iuc_proof iuc_pf_before(m, res.get(), core_lits);
 | 
			
		||||
                    iuc_pf_before.display_dot(ofs);
 | 
			
		||||
                    ofs.close();
 | 
			
		||||
 | 
			
		||||
                    proof_checker pc(m);
 | 
			
		||||
                    expr_ref_vector side(m);
 | 
			
		||||
                    ENSURE(pc.check(res, side));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
            scoped_watch _t_ (m_hyp_reduce2_sw);
 | 
			
		||||
 | 
			
		||||
            // pre-process proof for better iuc extraction
 | 
			
		||||
| 
						 | 
				
			
			@ -374,22 +356,6 @@ void iuc_solver::get_iuc(expr_ref_vector &core)
 | 
			
		|||
 | 
			
		||||
        iuc_proof iuc_pf(m, res, core_lits);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
        static unsigned cnt = 0;
 | 
			
		||||
        {
 | 
			
		||||
            cnt++;
 | 
			
		||||
            TRACE("spacer", tout << "Dumping pf cnt: " << cnt << "\n";);
 | 
			
		||||
            if (cnt == 123) {
 | 
			
		||||
                std::ofstream ofs;
 | 
			
		||||
                ofs.open("/tmp/pf_" + std::to_string(cnt) + ".dot");
 | 
			
		||||
                iuc_pf.display_dot(ofs);
 | 
			
		||||
                ofs.close();
 | 
			
		||||
                proof_checker pc(m);
 | 
			
		||||
                expr_ref_vector side(m);
 | 
			
		||||
                ENSURE(pc.check(res, side));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        unsat_core_learner learner(m, iuc_pf);
 | 
			
		||||
 | 
			
		||||
        unsat_core_plugin* plugin;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -785,7 +785,7 @@ namespace {
 | 
			
		|||
 | 
			
		||||
    void ground_expr(expr *e, expr_ref &out, app_ref_vector &vars) {
 | 
			
		||||
        expr_free_vars fv;
 | 
			
		||||
        ast_manager &m = out.get_manager();
 | 
			
		||||
        ast_manager &m = out.m();
 | 
			
		||||
 | 
			
		||||
        fv(e);
 | 
			
		||||
        if (vars.size() < fv.size()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -795,7 +795,7 @@ namespace {
 | 
			
		|||
            sort *s = fv[i] ? fv[i] : m.mk_bool_sort();
 | 
			
		||||
            vars[i] = mk_zk_const(m, i, s);
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(e, vars.size(),(expr * *) vars.c_ptr(), out);
 | 
			
		||||
            out = vs(e, vars.size(),(expr * *) vars.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -561,13 +561,13 @@ namespace tb {
 | 
			
		|||
                }
 | 
			
		||||
                vars.push_back(m.mk_const(symbol(i), sorts[i]));
 | 
			
		||||
            }
 | 
			
		||||
            vs(g.get_head(), vars.size(), vars.c_ptr(), fml);
 | 
			
		||||
            fml = vs(g.get_head(), vars.size(), vars.c_ptr());
 | 
			
		||||
            m_head = to_app(fml);
 | 
			
		||||
            for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
 | 
			
		||||
                vs(g.get_predicate(i), vars.size(), vars.c_ptr(), fml);
 | 
			
		||||
                fml = vs(g.get_predicate(i), vars.size(), vars.c_ptr());
 | 
			
		||||
                m_preds.push_back(to_app(fml));
 | 
			
		||||
            }
 | 
			
		||||
            vs(g.get_constraint(), vars.size(), vars.c_ptr(), fml);
 | 
			
		||||
            fml = vs(g.get_constraint(), vars.size(), vars.c_ptr());
 | 
			
		||||
            fmls.push_back(fml);
 | 
			
		||||
            m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
 | 
			
		||||
            IF_VERBOSE(2,
 | 
			
		||||
| 
						 | 
				
			
			@ -1132,12 +1132,12 @@ namespace tb {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (change) {
 | 
			
		||||
                m_S2(result->get_constraint(), m_rename.size(), m_rename.c_ptr(), constraint);
 | 
			
		||||
                constraint = m_S2(result->get_constraint(), m_rename.size(), m_rename.c_ptr());
 | 
			
		||||
                for (unsigned i = 0; i < result->get_num_predicates(); ++i) {
 | 
			
		||||
                    m_S2(result->get_predicate(i), m_rename.size(), m_rename.c_ptr(), tmp);
 | 
			
		||||
                    tmp = m_S2(result->get_predicate(i), m_rename.size(), m_rename.c_ptr());
 | 
			
		||||
                    predicates[i] = to_app(tmp);
 | 
			
		||||
                }
 | 
			
		||||
                m_S2(result->get_head(), m_rename.size(), m_rename.c_ptr(), tmp);
 | 
			
		||||
                tmp = m_S2(result->get_head(), m_rename.size(), m_rename.c_ptr());
 | 
			
		||||
                head = to_app(tmp);
 | 
			
		||||
                result->init(head, predicates, constraint);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1168,7 +1168,7 @@ namespace tb {
 | 
			
		|||
                if (vars[i]) {
 | 
			
		||||
                    v = m.mk_var(i, vars[i]);
 | 
			
		||||
                    m_S1.apply(2, delta, expr_offset(v, offset), tmp);
 | 
			
		||||
                    m_S2(tmp, m_rename.size(), m_rename.c_ptr(), tmp);
 | 
			
		||||
                    tmp = m_S2(tmp, m_rename.size(), m_rename.c_ptr());
 | 
			
		||||
                    insert_subst(offset, tmp);
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1613,8 +1613,8 @@ namespace datalog {
 | 
			
		|||
            }
 | 
			
		||||
            expr_ref body = clause.get_body();
 | 
			
		||||
            var_subst vs(m, false);
 | 
			
		||||
            vs(body, subst.size(), subst.c_ptr(), body);
 | 
			
		||||
            out << mk_pp(body, m) << "\n";
 | 
			
		||||
            body = vs(body, subst.size(), subst.c_ptr());
 | 
			
		||||
            out << body << "\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ namespace datalog {
 | 
			
		|||
        }
 | 
			
		||||
        var_subst vs(m, false);
 | 
			
		||||
        for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i) {
 | 
			
		||||
            vs(r->get_tail(i), revsub.size(), revsub.c_ptr(), result);
 | 
			
		||||
            result = vs(r->get_tail(i), revsub.size(), revsub.c_ptr());
 | 
			
		||||
            conjs.push_back(result);
 | 
			
		||||
        }
 | 
			
		||||
        bwr.mk_and(conjs.size(), conjs.c_ptr(), result);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,8 +156,7 @@ namespace datalog {
 | 
			
		|||
                SASSERT(m_binding[i]);
 | 
			
		||||
            });
 | 
			
		||||
        m_binding.reverse();
 | 
			
		||||
        expr_ref res(m);
 | 
			
		||||
        instantiate(m, q, m_binding.c_ptr(), res);
 | 
			
		||||
        expr_ref res = instantiate(m, q, m_binding.c_ptr());
 | 
			
		||||
        m_binding.reverse();
 | 
			
		||||
        m_cnst2var(res);
 | 
			
		||||
        conjs.push_back(res);
 | 
			
		||||
| 
						 | 
				
			
			@ -222,10 +221,7 @@ namespace datalog {
 | 
			
		|||
        for (unsigned i = 0; i < qs.size(); ++i) {
 | 
			
		||||
            instantiate_quantifier(qs[i].get(), conjs);
 | 
			
		||||
        }
 | 
			
		||||
        obj_map<func_decl, ptr_vector<expr>*>::iterator it = m_funs.begin(), end = m_funs.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            dealloc(it->m_value);
 | 
			
		||||
        }
 | 
			
		||||
        for (auto & kv : m_funs) dealloc(kv.m_value);
 | 
			
		||||
        m_funs.reset();
 | 
			
		||||
 | 
			
		||||
        fml = m.mk_and(conjs.size(), conjs.c_ptr());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ namespace datalog {
 | 
			
		|||
                    // Hedge that we don't have to handle the general case for models produced
 | 
			
		||||
                    // by Horn clause solvers.
 | 
			
		||||
                    SASSERT(!new_fi->is_partial() && new_fi->num_entries() == 0);
 | 
			
		||||
                    vs(new_fi->get_else(), subst.size(), subst.c_ptr(), tmp);
 | 
			
		||||
                    tmp = vs(new_fi->get_else(), subst.size(), subst.c_ptr());
 | 
			
		||||
                    old_fi->set_else(tmp);
 | 
			
		||||
                    old_model->register_decl(old_p, old_fi);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -352,7 +352,7 @@ namespace datalog {
 | 
			
		|||
                    }
 | 
			
		||||
                    if (!new_fi->is_partial()) {
 | 
			
		||||
                        TRACE("dl", tout << mk_pp(new_fi->get_else(), m) << "\n";);
 | 
			
		||||
                        vs(new_fi->get_else(), subst.size(), subst.c_ptr(), tmp);
 | 
			
		||||
                        tmp = vs(new_fi->get_else(), subst.size(), subst.c_ptr());
 | 
			
		||||
                        old_fi->set_else(tmp);
 | 
			
		||||
                    }
 | 
			
		||||
                    unsigned num_entries = new_fi->num_entries();
 | 
			
		||||
| 
						 | 
				
			
			@ -362,7 +362,7 @@ namespace datalog {
 | 
			
		|||
                        func_entry const* e = new_fi->get_entry(j);
 | 
			
		||||
                        for (unsigned k = 0, l = 0; k < old_p->get_arity(); ++k) {
 | 
			
		||||
                            if (!is_sliced.get(k)) {
 | 
			
		||||
                                vs(e->get_arg(l++), subst.size(), subst.c_ptr(), tmp);
 | 
			
		||||
                                tmp = vs(e->get_arg(l++), subst.size(), subst.c_ptr());
 | 
			
		||||
                                args.push_back(tmp);
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
| 
						 | 
				
			
			@ -370,7 +370,7 @@ namespace datalog {
 | 
			
		|||
                            }
 | 
			
		||||
                            SASSERT(l <= new_p->get_arity());
 | 
			
		||||
                        }
 | 
			
		||||
                        vs(e->get_result(), subst.size(), subst.c_ptr(), res);
 | 
			
		||||
                        res = vs(e->get_result(), subst.size(), subst.c_ptr());
 | 
			
		||||
                        old_fi->insert_entry(args.c_ptr(), res.get());
 | 
			
		||||
                    }
 | 
			
		||||
                    old_model->register_decl(old_p, old_fi);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -449,7 +449,6 @@ namespace opt {
 | 
			
		|||
        }
 | 
			
		||||
        lbool r = maxsmt();
 | 
			
		||||
        if (r == l_true) {
 | 
			
		||||
            ast_manager& m = m_solver->get_manager();
 | 
			
		||||
            svector<symbol> labels;
 | 
			
		||||
            maxsmt.get_model(m_model, labels);
 | 
			
		||||
            // TBD: is m_fm applied or not?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,7 @@ namespace smt2 {
 | 
			
		|||
        symbol               m_bang;
 | 
			
		||||
        symbol               m_forall;
 | 
			
		||||
        symbol               m_exists;
 | 
			
		||||
        symbol               m_lambda;
 | 
			
		||||
        symbol               m_as;
 | 
			
		||||
        symbol               m_not;
 | 
			
		||||
        symbol               m_root_obj;
 | 
			
		||||
| 
						 | 
				
			
			@ -161,7 +162,7 @@ namespace smt2 {
 | 
			
		|||
        };
 | 
			
		||||
 | 
			
		||||
        struct quant_frame : public expr_frame {
 | 
			
		||||
            bool     m_forall;
 | 
			
		||||
            quantifier_kind m_kind;
 | 
			
		||||
            symbol   m_qid;
 | 
			
		||||
            symbol   m_skid;
 | 
			
		||||
            unsigned m_weight;
 | 
			
		||||
| 
						 | 
				
			
			@ -170,8 +171,8 @@ namespace smt2 {
 | 
			
		|||
            unsigned m_sym_spos;
 | 
			
		||||
            unsigned m_sort_spos;
 | 
			
		||||
            unsigned m_expr_spos;
 | 
			
		||||
            quant_frame(bool forall, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos):
 | 
			
		||||
                expr_frame(EF_QUANT), m_forall(forall), m_weight(1),
 | 
			
		||||
            quant_frame(quantifier_kind k, unsigned pat_spos, unsigned nopat_spos, unsigned sym_spos, unsigned sort_spos, unsigned expr_spos):
 | 
			
		||||
                expr_frame(EF_QUANT), m_kind(k), m_weight(1),
 | 
			
		||||
                m_pat_spos(pat_spos), m_nopat_spos(nopat_spos),
 | 
			
		||||
                m_sym_spos(sym_spos), m_sort_spos(sort_spos),
 | 
			
		||||
                m_expr_spos(expr_spos) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -407,6 +408,7 @@ namespace smt2 {
 | 
			
		|||
        bool curr_id_is_match() const { SASSERT(curr_is_identifier()); return curr_id() == m_match; }
 | 
			
		||||
        bool curr_id_is_forall() const { SASSERT(curr_is_identifier()); return curr_id() == m_forall; }
 | 
			
		||||
        bool curr_id_is_exists() const { SASSERT(curr_is_identifier()); return curr_id() == m_exists; }
 | 
			
		||||
        bool curr_id_is_lambda() const { SASSERT(curr_is_identifier()); return curr_id() == m_lambda; }
 | 
			
		||||
        bool curr_id_is_bang() const { SASSERT(curr_is_identifier()); return curr_id() == m_bang; }
 | 
			
		||||
        bool curr_id_is_let() const { SASSERT(curr_is_identifier()); return curr_id() == m_let; }
 | 
			
		||||
        bool curr_id_is_root_obj() const { SASSERT(curr_is_identifier()); return curr_id() == m_root_obj; }
 | 
			
		||||
| 
						 | 
				
			
			@ -1301,15 +1303,15 @@ namespace smt2 {
 | 
			
		|||
            m_num_expr_frames++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        void push_quant_frame(bool is_forall) {
 | 
			
		||||
        void push_quant_frame(quantifier_kind k) {
 | 
			
		||||
            SASSERT(curr_is_identifier());
 | 
			
		||||
            SASSERT(curr_id_is_forall() || curr_id_is_exists());
 | 
			
		||||
            SASSERT(!is_forall || curr_id_is_forall());
 | 
			
		||||
            SASSERT(is_forall || curr_id_is_exists());
 | 
			
		||||
            SASSERT(curr_id_is_forall() || curr_id_is_exists() || curr_id_is_lambda());
 | 
			
		||||
            SASSERT((k == forall_k) == curr_id_is_forall());
 | 
			
		||||
            SASSERT((k == exists_k) == curr_id_is_exists());
 | 
			
		||||
            SASSERT((k == lambda_k) == curr_id_is_lambda());
 | 
			
		||||
            next();
 | 
			
		||||
            void * mem      = m_stack.allocate(sizeof(quant_frame));
 | 
			
		||||
            new (mem) quant_frame(is_forall, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(),
 | 
			
		||||
            new (mem) quant_frame(k, pattern_stack().size(), nopattern_stack().size(), symbol_stack().size(),
 | 
			
		||||
                                  sort_stack().size(), expr_stack().size());
 | 
			
		||||
            m_num_expr_frames++;
 | 
			
		||||
            unsigned num_vars = parse_sorted_vars();
 | 
			
		||||
| 
						 | 
				
			
			@ -1374,7 +1376,7 @@ namespace smt2 {
 | 
			
		|||
                    new_case = cases[i];
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    sub(cases[i], subst.size(), subst.c_ptr(), new_case);
 | 
			
		||||
                    new_case = sub(cases[i], subst.size(), subst.c_ptr());
 | 
			
		||||
                    inv_var_shifter inv(m());
 | 
			
		||||
                    inv(new_case, subst.size(), new_case);
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -1815,10 +1817,13 @@ namespace smt2 {
 | 
			
		|||
                    push_let_frame();
 | 
			
		||||
                }
 | 
			
		||||
                else if (curr_id_is_forall()) {
 | 
			
		||||
                    push_quant_frame(true);
 | 
			
		||||
                    push_quant_frame(forall_k);
 | 
			
		||||
                }
 | 
			
		||||
                else if (curr_id_is_exists()) {
 | 
			
		||||
                    push_quant_frame(false);
 | 
			
		||||
                    push_quant_frame(exists_k);
 | 
			
		||||
                }
 | 
			
		||||
                else if (curr_id_is_lambda()) {
 | 
			
		||||
                    push_quant_frame(lambda_k);
 | 
			
		||||
                }
 | 
			
		||||
                else if (curr_id_is_bang()) {
 | 
			
		||||
                    push_bang_frame(curr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1915,6 +1920,7 @@ namespace smt2 {
 | 
			
		|||
            SASSERT(expr_stack().size() >= fr->m_expr_spos);
 | 
			
		||||
            unsigned num_decls  = sort_stack().size() - fr->m_sort_spos;
 | 
			
		||||
            if (expr_stack().size() - fr->m_expr_spos != num_decls /* variables */ + 1 /* result */)
 | 
			
		||||
                //throw parser_exception("invalid quantified expression, syntax error: (forall|exists|lambda ((<symbol> <sort>)*) <expr>) expected");
 | 
			
		||||
                throw parser_exception("invalid quantified expression, syntax error: (forall|exists ((<symbol> <sort>)*) <expr>) expected");
 | 
			
		||||
            unsigned begin_pats = fr->m_pat_spos;
 | 
			
		||||
            unsigned end_pats   = pattern_stack().size();
 | 
			
		||||
| 
						 | 
				
			
			@ -1938,19 +1944,19 @@ namespace smt2 {
 | 
			
		|||
            TRACE("parse_quantifier", tout << "body:\n" << mk_pp(expr_stack().back(), m()) << "\n";);
 | 
			
		||||
            if (fr->m_qid == symbol::null)
 | 
			
		||||
                fr->m_qid = symbol(m_scanner.get_line());
 | 
			
		||||
            if (!m().is_bool(expr_stack().back()))
 | 
			
		||||
            if (fr->m_kind != lambda_k && !m().is_bool(expr_stack().back()))
 | 
			
		||||
                throw parser_exception("quantifier body must be a Boolean expression");
 | 
			
		||||
            quantifier * new_q = m().mk_quantifier(fr->m_forall,
 | 
			
		||||
                                                   num_decls,
 | 
			
		||||
                                                   sort_stack().c_ptr() + fr->m_sort_spos,
 | 
			
		||||
                                                   symbol_stack().c_ptr() + fr->m_sym_spos,
 | 
			
		||||
                                                   expr_stack().back(),
 | 
			
		||||
                                                   fr->m_weight,
 | 
			
		||||
                                                   fr->m_qid,
 | 
			
		||||
                                                   fr->m_skid,
 | 
			
		||||
                                                   num_pats, pattern_stack().c_ptr() + fr->m_pat_spos,
 | 
			
		||||
                                                   num_nopats, nopattern_stack().c_ptr() + fr->m_nopat_spos
 | 
			
		||||
                                                   );
 | 
			
		||||
            quantifier* new_q = m().mk_quantifier(fr->m_kind,
 | 
			
		||||
                                      num_decls,
 | 
			
		||||
                                      sort_stack().c_ptr() + fr->m_sort_spos,
 | 
			
		||||
                                      symbol_stack().c_ptr() + fr->m_sym_spos,
 | 
			
		||||
                                      expr_stack().back(),
 | 
			
		||||
                                      fr->m_weight,
 | 
			
		||||
                                      fr->m_qid,
 | 
			
		||||
                                      fr->m_skid,
 | 
			
		||||
                                      num_pats, pattern_stack().c_ptr() + fr->m_pat_spos,
 | 
			
		||||
                                      num_nopats, nopattern_stack().c_ptr() + fr->m_nopat_spos
 | 
			
		||||
                                      );
 | 
			
		||||
            TRACE("mk_quantifier", tout << "id: " << new_q->get_id() << "\n" << mk_ismt2_pp(new_q, m()) << "\n";);
 | 
			
		||||
            TRACE("skid", tout << "new_q->skid: " << new_q->get_skid() << "\n";);
 | 
			
		||||
            expr_stack().shrink(fr->m_expr_spos);
 | 
			
		||||
| 
						 | 
				
			
			@ -2965,6 +2971,7 @@ namespace smt2 {
 | 
			
		|||
            m_bang("!"),
 | 
			
		||||
            m_forall("forall"),
 | 
			
		||||
            m_exists("exists"),
 | 
			
		||||
            m_lambda("lambda"),
 | 
			
		||||
            m_as("as"),
 | 
			
		||||
            m_not("not"),
 | 
			
		||||
            m_root_obj("root-obj"),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2269,8 +2269,7 @@ namespace qe {
 | 
			
		|||
                bound.push_back(m.mk_fresh_const("bound", fv[i]));
 | 
			
		||||
            }
 | 
			
		||||
            var_subst subst(m);
 | 
			
		||||
            subst(fml, bound.size(), bound.c_ptr(), tmp);
 | 
			
		||||
            fml = tmp;
 | 
			
		||||
            fml = subst(fml, bound.size(), bound.c_ptr());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2291,7 +2290,7 @@ namespace qe {
 | 
			
		|||
        }
 | 
			
		||||
        expr* const* exprs = (expr* const*)(vars.c_ptr());
 | 
			
		||||
        var_subst subst(m);
 | 
			
		||||
        subst(new_body, vars.size(), exprs, tmp);
 | 
			
		||||
        tmp = subst(new_body, vars.size(), exprs);
 | 
			
		||||
        inv_var_shifter shift(m);
 | 
			
		||||
        shift(tmp, vars.size(), new_body);        
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -2337,13 +2336,18 @@ namespace qe {
 | 
			
		|||
            case AST_QUANTIFIER: {
 | 
			
		||||
                app_ref_vector vars(m);
 | 
			
		||||
                quantifier* q = to_quantifier(e);
 | 
			
		||||
                bool is_fa = q->is_forall();
 | 
			
		||||
                tmp = q->get_expr();
 | 
			
		||||
                extract_vars(q, tmp, vars);
 | 
			
		||||
                elim(tmp);
 | 
			
		||||
                init_qe();
 | 
			
		||||
                m_qe->set_assumption(m_assumption);
 | 
			
		||||
                m_qe->eliminate(is_fa, vars.size(), vars.c_ptr(), tmp);
 | 
			
		||||
                if (is_lambda(q)) {
 | 
			
		||||
                    tmp = e;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    bool is_fa = is_forall(q);
 | 
			
		||||
                    tmp = q->get_expr();
 | 
			
		||||
                    extract_vars(q, tmp, vars);
 | 
			
		||||
                    elim(tmp);
 | 
			
		||||
                    init_qe();
 | 
			
		||||
                    m_qe->set_assumption(m_assumption);
 | 
			
		||||
                    m_qe->eliminate(is_fa, vars.size(), vars.c_ptr(), tmp);
 | 
			
		||||
                }
 | 
			
		||||
                m_trail.push_back(tmp);
 | 
			
		||||
                m_visited.insert(e, tmp);
 | 
			
		||||
                todo.pop_back();
 | 
			
		||||
| 
						 | 
				
			
			@ -2593,6 +2597,9 @@ namespace qe {
 | 
			
		|||
            ) 
 | 
			
		||||
        {
 | 
			
		||||
            
 | 
			
		||||
            if (is_lambda(old_q)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            // bool is_forall = old_q->is_forall();
 | 
			
		||||
            app_ref_vector vars(m);
 | 
			
		||||
            TRACE("qe", tout << "simplifying" << mk_pp(new_body, m) << "\n";);
 | 
			
		||||
| 
						 | 
				
			
			@ -2600,11 +2607,11 @@ namespace qe {
 | 
			
		|||
            extract_vars(old_q, result, vars);
 | 
			
		||||
            TRACE("qe", tout << "variables extracted" << mk_pp(result, m) << "\n";);
 | 
			
		||||
 | 
			
		||||
            if (old_q->is_forall()) {
 | 
			
		||||
            if (is_forall(old_q)) {
 | 
			
		||||
                result = mk_not(m, result);
 | 
			
		||||
            }
 | 
			
		||||
            m_ctx.solve(result, vars);
 | 
			
		||||
            if (old_q->is_forall()) {
 | 
			
		||||
            if (is_forall(old_q)) {
 | 
			
		||||
                expr* e = nullptr;
 | 
			
		||||
                result = m.is_not(result, e)?e:mk_not(m, result);
 | 
			
		||||
            }       
 | 
			
		||||
| 
						 | 
				
			
			@ -2619,7 +2626,7 @@ namespace qe {
 | 
			
		|||
                names.push_back(vars[i]->get_decl()->get_name());
 | 
			
		||||
            }
 | 
			
		||||
            if (!vars.empty()) {
 | 
			
		||||
                result = m.mk_quantifier(old_q->is_forall(), vars.size(), sorts.c_ptr(), names.c_ptr(), result, 1);
 | 
			
		||||
                result = m.mk_quantifier(old_q->get_kind(), vars.size(), sorts.c_ptr(), names.c_ptr(), result, 1);
 | 
			
		||||
            }            
 | 
			
		||||
            result_pr = nullptr;
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -327,8 +327,8 @@ namespace eq {
 | 
			
		|||
 | 
			
		||||
        void flatten_args(quantifier* q, unsigned& num_args, expr*const*& args) {
 | 
			
		||||
            expr * e = q->get_expr();
 | 
			
		||||
            if ((q->is_forall() && m.is_or(e)) ||
 | 
			
		||||
                (q->is_exists() && m.is_and(e))) {
 | 
			
		||||
            if ((is_forall(q) && m.is_or(e)) ||
 | 
			
		||||
                (is_exists(q) && m.is_and(e))) {
 | 
			
		||||
                num_args = to_app(e)->get_num_args();
 | 
			
		||||
                args     = to_app(e)->get_args();
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -356,27 +356,29 @@ namespace eq {
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            expr_ref t(m);
 | 
			
		||||
            if (q->is_forall()) {
 | 
			
		||||
            switch (q->get_kind()) {
 | 
			
		||||
            case forall_k:
 | 
			
		||||
                rw.mk_or(m_new_args.size(), m_new_args.c_ptr(), t);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                break;
 | 
			
		||||
            case exists_k:
 | 
			
		||||
                rw.mk_and(m_new_args.size(), m_new_args.c_ptr(), t);
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                t = e;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            expr_ref new_e(m);
 | 
			
		||||
            m_subst(t, new_e);
 | 
			
		||||
            expr_ref new_e = m_subst(t, m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
 | 
			
		||||
            // don't forget to update the quantifier patterns
 | 
			
		||||
            expr_ref_buffer  new_patterns(m);
 | 
			
		||||
            expr_ref_buffer  new_no_patterns(m);
 | 
			
		||||
            for (unsigned j = 0; j < q->get_num_patterns(); j++) {
 | 
			
		||||
                expr_ref new_pat(m);
 | 
			
		||||
                m_subst(q->get_pattern(j), new_pat);
 | 
			
		||||
                expr_ref new_pat = m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
                new_patterns.push_back(new_pat);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
 | 
			
		||||
                expr_ref new_nopat(m);
 | 
			
		||||
                m_subst(q->get_no_pattern(j), new_nopat);
 | 
			
		||||
                expr_ref new_nopat = m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
                new_no_patterns.push_back(new_nopat);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -390,12 +392,17 @@ namespace eq {
 | 
			
		|||
            set_is_variable_proc(is_v);
 | 
			
		||||
            unsigned num_args = 1;
 | 
			
		||||
            expr* const* args = &e;
 | 
			
		||||
            if (is_lambda(q)) {
 | 
			
		||||
                r = q;
 | 
			
		||||
                pr = 0;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            flatten_args(q, num_args, args);
 | 
			
		||||
 | 
			
		||||
            unsigned def_count = 0;
 | 
			
		||||
            unsigned largest_vinx = 0;
 | 
			
		||||
 | 
			
		||||
            find_definitions(num_args, args, q->is_exists(), def_count, largest_vinx);
 | 
			
		||||
            find_definitions(num_args, args, is_exists(q), def_count, largest_vinx);
 | 
			
		||||
 | 
			
		||||
            if (def_count > 0) {
 | 
			
		||||
                get_elimination_order();
 | 
			
		||||
| 
						 | 
				
			
			@ -423,7 +430,7 @@ namespace eq {
 | 
			
		|||
            if (is_quantifier(r)) {
 | 
			
		||||
                quantifier * q = to_quantifier(r);
 | 
			
		||||
 | 
			
		||||
                ::elim_unused_vars(m, q, m_params, r);
 | 
			
		||||
                r = ::elim_unused_vars(m, q, m_params);
 | 
			
		||||
                if (m.proofs_enabled()) {
 | 
			
		||||
                    proof * p1 = m.mk_elim_unused_vars(q, r);
 | 
			
		||||
                    pr = m.mk_transitivity(pr, p1);
 | 
			
		||||
| 
						 | 
				
			
			@ -624,7 +631,7 @@ namespace eq {
 | 
			
		|||
                    expr_ref r(m), new_r(m);
 | 
			
		||||
                    r = m.mk_and(conjs.size(), conjs.c_ptr());
 | 
			
		||||
                    create_substitution(largest_vinx + 1);
 | 
			
		||||
                    m_subst(r, new_r);
 | 
			
		||||
                    new_r = m_subst(r, m_subst_map.size(), m_subst_map.c_ptr());
 | 
			
		||||
                    m_rewriter(new_r);
 | 
			
		||||
                    conjs.reset();
 | 
			
		||||
                    flatten_and(new_r, conjs);
 | 
			
		||||
| 
						 | 
				
			
			@ -1756,16 +1763,12 @@ namespace fm {
 | 
			
		|||
            // x_cost_lt is not a total order on variables
 | 
			
		||||
            std::stable_sort(x_cost_vector.begin(), x_cost_vector.end(), x_cost_lt(m_is_int));
 | 
			
		||||
            TRACE("qe_lite",
 | 
			
		||||
                  svector<x_cost>::iterator it2  = x_cost_vector.begin();
 | 
			
		||||
                  svector<x_cost>::iterator end2 = x_cost_vector.end();
 | 
			
		||||
                  for (; it2 != end2; ++it2) {
 | 
			
		||||
                      tout << "(" << mk_ismt2_pp(m_var2expr.get(it2->first), m) << " " << it2->second << ") ";
 | 
			
		||||
                  for (auto const& kv : x_cost_vector) {
 | 
			
		||||
                      tout << "(" << mk_ismt2_pp(m_var2expr.get(kv.first), m) << " " << kv.second << ") ";
 | 
			
		||||
                  }
 | 
			
		||||
                  tout << "\n";);
 | 
			
		||||
            svector<x_cost>::iterator it2  = x_cost_vector.begin();
 | 
			
		||||
            svector<x_cost>::iterator end2 = x_cost_vector.end();
 | 
			
		||||
            for (; it2 != end2; ++it2) {
 | 
			
		||||
                xs.push_back(it2->first);
 | 
			
		||||
            for (auto const& kv : x_cost_vector) {
 | 
			
		||||
                xs.push_back(kv.first);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1802,11 +1805,9 @@ namespace fm {
 | 
			
		|||
        void analyze(constraints const & cs, var x, bool & all_int, bool & unit_coeff) const {
 | 
			
		||||
            all_int    = true;
 | 
			
		||||
            unit_coeff = true;
 | 
			
		||||
            constraints::const_iterator it  = cs.begin();
 | 
			
		||||
            constraints::const_iterator end = cs.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
            for (constraint const* c : cs) {
 | 
			
		||||
                bool curr_unit_coeff;
 | 
			
		||||
                analyze(*(*it), x, all_int, curr_unit_coeff);
 | 
			
		||||
                analyze(*c, x, all_int, curr_unit_coeff);
 | 
			
		||||
                if (!all_int)
 | 
			
		||||
                    return;
 | 
			
		||||
                if (!curr_unit_coeff)
 | 
			
		||||
| 
						 | 
				
			
			@ -1830,10 +1831,8 @@ namespace fm {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        void copy_constraints(constraints const & s, clauses & t) {
 | 
			
		||||
            constraints::const_iterator it  = s.begin();
 | 
			
		||||
            constraints::const_iterator end = s.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                app * c = to_expr(*(*it));
 | 
			
		||||
            for (constraint const* cns : s) {
 | 
			
		||||
                app * c = to_expr(*cns);
 | 
			
		||||
                t.push_back(c);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1842,10 +1841,8 @@ namespace fm {
 | 
			
		|||
        void save_constraints(var x) {  }
 | 
			
		||||
 | 
			
		||||
        void mark_constraints_dead(constraints const & cs) {
 | 
			
		||||
            constraints::const_iterator it  = cs.begin();
 | 
			
		||||
            constraints::const_iterator end = cs.end();
 | 
			
		||||
            for (; it != end; ++it)
 | 
			
		||||
                (*it)->m_dead = true;
 | 
			
		||||
            for (constraint* c : cs) 
 | 
			
		||||
                c->m_dead = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void mark_constraints_dead(var x) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2094,14 +2091,8 @@ namespace fm {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        void copy_remaining(vector<constraints> & v2cs) {
 | 
			
		||||
            vector<constraints>::iterator it  = v2cs.begin();
 | 
			
		||||
            vector<constraints>::iterator end = v2cs.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                constraints & cs = *it;
 | 
			
		||||
                constraints::iterator it2  = cs.begin();
 | 
			
		||||
                constraints::iterator end2 = cs.end();
 | 
			
		||||
                for (; it2 != end2; ++it2) {
 | 
			
		||||
                    constraint * c = *it2;
 | 
			
		||||
            for (constraints& cs : v2cs) {
 | 
			
		||||
                for (constraint* c : cs) {
 | 
			
		||||
                    if (!c->m_dead) {
 | 
			
		||||
                        c->m_dead = true;
 | 
			
		||||
                        expr * new_f = to_expr(*c);
 | 
			
		||||
| 
						 | 
				
			
			@ -2170,11 +2161,8 @@ namespace fm {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        void display_constraints(std::ostream & out, constraints const & cs) const {
 | 
			
		||||
            constraints::const_iterator it  = cs.begin();
 | 
			
		||||
            constraints::const_iterator end = cs.end();
 | 
			
		||||
            for (; it != end; ++it) {
 | 
			
		||||
                out << "  ";
 | 
			
		||||
                display(out, *(*it));
 | 
			
		||||
            for (constraint const* c : cs) {
 | 
			
		||||
                display(out << "  ", *c);
 | 
			
		||||
                out << "\n";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -2215,7 +2203,9 @@ public:
 | 
			
		|||
            for (unsigned i = 0; i < q->get_num_decls(); ++i) {
 | 
			
		||||
                indices.insert(i);
 | 
			
		||||
            }
 | 
			
		||||
            m_imp(indices, true, result);
 | 
			
		||||
            if (q->get_kind() != lambda_k) {
 | 
			
		||||
                m_imp(indices, true, result);
 | 
			
		||||
            }
 | 
			
		||||
            if (is_forall(q)) {
 | 
			
		||||
                result = push_not(result);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -2295,7 +2285,7 @@ public:
 | 
			
		|||
            tmp = to_quantifier(tmp)->get_expr();
 | 
			
		||||
            used.process(tmp);
 | 
			
		||||
            var_subst vs(m, true);
 | 
			
		||||
            vs(tmp, vars.size(), (expr*const*)vars.c_ptr(), fml);
 | 
			
		||||
            fml = vs(tmp, vars.size(), (expr*const*)vars.c_ptr());
 | 
			
		||||
            // collect set of variables that were used.
 | 
			
		||||
            unsigned j = 0;
 | 
			
		||||
            for (unsigned i = 0; i < vars.size(); ++i) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ Revision History:
 | 
			
		|||
#include "qe/qe_arrays.h"
 | 
			
		||||
#include "qe/qe_datatypes.h"
 | 
			
		||||
#include "qe/qe_lite.h"
 | 
			
		||||
#include "model/model_pp.h"
 | 
			
		||||
#include "model/model_evaluator.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -616,7 +617,7 @@ public:
 | 
			
		|||
            qe::array_project_plugin ap(m);
 | 
			
		||||
            ap(mdl, array_vars, fml, vars, m_reduce_all_selects);
 | 
			
		||||
            SASSERT (array_vars.empty ());
 | 
			
		||||
            m_rw(fml);
 | 
			
		||||
            m_rw (fml);
 | 
			
		||||
            SASSERT (!m.is_false (fml));
 | 
			
		||||
 | 
			
		||||
            TRACE ("qe",
 | 
			
		||||
| 
						 | 
				
			
			@ -650,9 +651,9 @@ public:
 | 
			
		|||
        // substitute any remaining other vars
 | 
			
		||||
        if (!m_dont_sub && !other_vars.empty ()) {
 | 
			
		||||
            subst_vars (eval, other_vars, fml);
 | 
			
		||||
            TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";);
 | 
			
		||||
            // an extra round of simplification because subst_vars is not simplifying
 | 
			
		||||
            m_rw(fml);
 | 
			
		||||
            TRACE ("qe", tout << "After substituting remaining other vars:\n" << fml << "\n";);
 | 
			
		||||
            other_vars.reset();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -989,9 +989,10 @@ namespace qe {
 | 
			
		|||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                case AST_QUANTIFIER: {
 | 
			
		||||
                    SASSERT(!is_lambda(e));
 | 
			
		||||
                    app_ref_vector vars(m);
 | 
			
		||||
                    quantifier* q = to_quantifier(e);
 | 
			
		||||
                    bool is_fa = q->is_forall();
 | 
			
		||||
                    bool is_fa = ::is_forall(q);
 | 
			
		||||
                    tmp = q->get_expr();
 | 
			
		||||
                    extract_vars(q, tmp, vars);
 | 
			
		||||
                    TRACE("qe", tout << vars << " " << mk_pp(q, m) << " " << tmp << "\n";);
 | 
			
		||||
| 
						 | 
				
			
			@ -1235,6 +1236,9 @@ namespace qe {
 | 
			
		|||
                fml = push_not(fml);
 | 
			
		||||
            }
 | 
			
		||||
            hoist(fml);
 | 
			
		||||
            if (!is_ground(fml)) {
 | 
			
		||||
                throw tactic_exception("formula is not hoistable");
 | 
			
		||||
            }
 | 
			
		||||
            m_pred_abs.abstract_atoms(fml, defs);
 | 
			
		||||
            fml = m_pred_abs.mk_abstract(fml);
 | 
			
		||||
            m_ex.assert_expr(mk_and(defs));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue