diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e55b329db..042099937 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -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 diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index 61c37ec3e..31391e218 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -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); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 34168f1f4..0753d3ffe 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -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; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 21c55f428..4bb146e39 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -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 { diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 6e0162024..b760760a4 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -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(types); + svector 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 _names; + ptr_vector _vars; + ptr_vector _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" { } }; + diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 951b9e51e..1c8d205bc 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -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); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 665ffb438..b68fb2021 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -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 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 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 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 _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) { diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs index e14bb1083..6c51bfc5b 100644 --- a/src/api/dotnet/ArrayExpr.cs +++ b/src/api/dotnet/ArrayExpr.cs @@ -37,6 +37,6 @@ namespace Microsoft.Z3 { Contract.Requires(ctx != null); } - #endregion + #endregion } } diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 76516bf39..50f643c8d 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -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 diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 38da21370..890d86619 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3292,6 +3292,53 @@ namespace Microsoft.Z3 return MkExists(boundConstants, body, weight, patterns, noPatterns, quantifierID, skolemID); } + /// + /// Create a lambda expression. + /// + /// + /// Creates a lambda expression. + /// is an array + /// with the sorts of the bound variables, is an array with the + /// 'names' of the bound variables, and is the body of the + /// lambda. + /// Note that the bound variables are de-Bruijn indices created using . + /// Z3 applies the convention that the last element in and + /// refers to the variable with index 0, the second to last element + /// of and refers to the variable + /// with index 1, etc. + /// + /// the sorts of the bound variables. + /// names of the bound variables + /// the body of the quantifier. + 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() != null); + return new Lambda(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) + { + Contract.Requires(body != null); + Contract.Requires(boundConstants != null && Contract.ForAll(boundConstants, b => b != null)); + Contract.Ensures(Contract.Result() != null); + return new Lambda(this, boundConstants, body); + } + + #endregion #endregion // Expr diff --git a/src/api/dotnet/Quantifier.cs b/src/api/dotnet/Quantifier.cs index eca4e3c7e..e34b4ef97 100644 --- a/src/api/dotnet/Quantifier.cs +++ b/src/api/dotnet/Quantifier.cs @@ -41,7 +41,7 @@ namespace Microsoft.Z3 /// public bool IsExistential { - get { return !IsUniversal; } + get { return Native.Z3_is_quantifier_exists(Context.nCtx, NativeObject) != 0; } } /// diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index 7f0774955..302b3d5bd 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -141,6 +141,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES IntNum.java IntSort.java IntSymbol.java + Lambda.java ListSort.java Log.java ModelDecRefQueue.java diff --git a/src/api/java/Context.java b/src/api/java/Context.java index dee9dbaf6..07be64230 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.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"/> = to every subgoal produced by evaluates to true and >> 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): diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 8fd0c182e..76614910f 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -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): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 3e47833b4..7e12f2fa7 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -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. diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 681f64a25..1b1be9b52 100644 --- a/src/ast/ast.cpp +++ b/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(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(get_decl_sorts()), decl_sorts, sizeof(sort *) * num_decls); + memcpy(const_cast(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 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 &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)); } diff --git a/src/ast/ast.h b/src/ast/ast.h index b6b71c6a3..aa8669def 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -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(m_patterns_decls); } symbol const * get_decl_names() const { return reinterpret_cast(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; } @@ -844,6 +859,7 @@ public: void set_no_unused_vars() { m_has_unused_vars = false; } 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 { @@ -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(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(n)->is_forall(); } -inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast(n)->is_exists(); } +inline bool is_forall(ast const * n) { return is_quantifier(n) && static_cast(n)->get_kind() == forall_k; } +inline bool is_exists(ast const * n) { return is_quantifier(n) && static_cast(n)->get_kind() == exists_k; } +inline bool is_lambda(ast const * n) { return is_quantifier(n) && static_cast(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); diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index cbdd94efb..7e2478347 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -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++) { diff --git a/src/ast/ast_lt.cpp b/src/ast/ast_lt.cpp index b6b52966e..a8d703259 100644 --- a/src/ast/ast_lt.cpp +++ b/src/ast/ast_lt.cpp @@ -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()); diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 9d27ffb24..6099d89dc 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -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(m(), fs, fs+2, f2f(), header, 1, SMALL_INDENT); info f_info = m_info_stack.back(); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 22adf42d9..2cce53e3a 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -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) { diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 5ab6ab351..278c2dff9 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -279,7 +279,7 @@ ast * ast_translation::process(ast const * _n) { expr ** pats = reinterpret_cast(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, diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index c45e445fd..022045a1d 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -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); } diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 2ddc69aaf..cc25905f0 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -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; diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index 5a46da65a..b7771110a 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -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& 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(); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 2f429ccf7..dd774772a 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -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); diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index b2f31e374..2858614d9 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -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; diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 3a0735e25..ee1b77545 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -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); } diff --git a/src/ast/normal_forms/defined_names.cpp b/src/ast/normal_forms/defined_names.cpp index eb6da9400..b63c947a9 100644 --- a/src/ast/normal_forms/defined_names.cpp +++ b/src/ast/normal_forms/defined_names.cpp @@ -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 expr2name; typedef obj_map 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 & 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 const & names, expr * def_conjunct, app * name, expr_ref & result); - void bound_vars(sort_ref_buffer const & sorts, buffer 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 const & var_names, expr_ref & new_def); + void bound_vars(sort_ref_buffer const & sorts, buffer const & names, expr * def_conjunct, app * name, expr_ref & result, symbol const& qid = symbol::null); + void bound_vars(sort_ref_buffer const & sorts, buffer 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 & 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 const & var_names, expr_ref & new_def) override; + void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer & 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 const & names, expr * def_conjunct, app * name, expr_ref & result) { +void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer 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 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 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 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 & 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 const & var_names, expr_ref & new_def) { + +void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer & 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 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 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(); diff --git a/src/ast/normal_forms/defined_names.h b/src/ast/normal_forms/defined_names.h index 764822f66..a3a603d21 100644 --- a/src/ast/normal_forms/defined_names.h +++ b/src/ast/normal_forms/defined_names.h @@ -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(); diff --git a/src/ast/normal_forms/name_exprs.cpp b/src/ast/normal_forms/name_exprs.cpp index 3e5503ea7..5e9af1c2d 100644 --- a/src/ast/normal_forms/name_exprs.cpp +++ b/src/ast/normal_forms/name_exprs.cpp @@ -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); } }; diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index c7f20ced6..7786def0b 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -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 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(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; } @@ -233,8 +237,8 @@ struct nnf::imp { #define POS_NQ_CIDX 1 // positive polarity and not nested in a quantifier #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 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); - else - return m().mk_nnf_pos(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); } - else - return m().mk_nnf_neg(old_e, new_e, num_parents, parents); + else + return m.mk_nnf_neg(old_e, new_e, num_parents, parents); } bool process_and_or(app * t, frame & fr) { @@ -473,11 +477,11 @@ 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); if (proofs_enabled()) { @@ -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,10 +530,10 @@ 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); if (proofs_enabled()) { @@ -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); @@ -614,10 +618,10 @@ struct nnf::imp { expr * not_rhs = rs[3]; 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)); + if (is_eq(t) == fr.m_pol) + 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(n2.get()), 1, prs); + pr2 = m.mk_oeq_congruence(m.mk_not(t), static_cast(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 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(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 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,13 +914,13 @@ 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); - new_def_proofs.push_back(new_pr); + proof * new_pr = m.mk_modus_ponens(m_todo_proofs.get(i), dpr); + new_def_proofs.push_back(new_pr); } } std::reverse(new_defs.c_ptr() + old_sz1, new_defs.c_ptr() + new_defs.size()); @@ -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) { diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 06881f97b..9ff75ca25 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -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 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; diff --git a/src/ast/pattern/expr_pattern_match.cpp b/src/ast/pattern/expr_pattern_match.cpp index c441fb4ce..47b3e9203 100644 --- a/src/ast/pattern/expr_pattern_match.cpp +++ b/src/ast/pattern/expr_pattern_match.cpp @@ -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()) { diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 3208a50fe..f6c8788d0 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -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";); } diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index e148299be..c98f63d28 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -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)) { - q = to_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)); diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp index 97213c235..5483a9ea0 100644 --- a/src/ast/proofs/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -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()); } }; diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index fb7783fe9..83749c82d 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -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])); diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index ba2c6547d..862d1cdab 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -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; diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 46613a12e..d61c906be 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -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; diff --git a/src/ast/rewriter/bv_elim.cpp b/src/ast/rewriter/bv_elim.cpp index 0c6484ed6..f5690b680 100644 --- a/src/ast/rewriter/bv_elim.cpp +++ b/src/ast/rewriter/bv_elim.cpp @@ -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(), diff --git a/src/ast/rewriter/der.cpp b/src/ast/rewriter/der.cpp index 54409e9c2..027846c31 100644 --- a/src/ast/rewriter/der.cpp +++ b/src/ast/rewriter/der.cpp @@ -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); } diff --git a/src/ast/rewriter/distribute_forall.cpp b/src/ast/rewriter/distribute_forall.cpp index 77db3bc28..54d7e2eca 100644 --- a/src/ast/rewriter/distribute_forall.cpp +++ b/src/ast/rewriter/distribute_forall.cpp @@ -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); diff --git a/src/ast/rewriter/elim_bounds.cpp b/src/ast/rewriter/elim_bounds.cpp index a640081ba..02d3217cf 100644 --- a/src/ast/rewriter/elim_bounds.cpp +++ b/src/ast/rewriter/elim_bounds.cpp @@ -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; diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index 814a25ee9..65250282c 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -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); diff --git a/src/ast/rewriter/inj_axiom.cpp b/src/ast/rewriter/inj_axiom.cpp index 184c84144..5fa60ad93 100644 --- a/src/ast/rewriter/inj_axiom.cpp +++ b/src/ast/rewriter/inj_axiom.cpp @@ -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) && diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index 2f1116299..3bd3cb3bc 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -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* sorts, svector* names, bool use_fresh, bool rewrite_ok) { + unsigned pull_quantifier(bool _is_forall, expr_ref& fml, ptr_vector* sorts, svector* 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; diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp index 4356f8f45..80b690428 100644 --- a/src/ast/rewriter/rewriter.cpp +++ b/src/ast/rewriter/rewriter.cpp @@ -208,12 +208,10 @@ void rewriter_core::cleanup() { #ifdef _TRACE void rewriter_core::display_stack(std::ostream & out, unsigned pp_depth) { - svector::iterator it = m_frame_stack.begin(); - svector::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"; } } diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index c761b5ca3..84fef488f 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -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); diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index e8a14b953..1a761e5d1 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -542,7 +542,7 @@ void rewriter_tpl::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); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 8f7b56381..568836abb 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -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: diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 912df0fc9..0f4be71c9 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -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) { diff --git a/src/ast/rewriter/th_rewriter.h b/src/ast/rewriter/th_rewriter.h index db495e8da..19a99f4d3 100644 --- a/src/ast/rewriter/th_rewriter.h +++ b/src/ast/rewriter/th_rewriter.h @@ -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); diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 7877cf1d2..cbd79e08c 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -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 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& todo, unsigned offset, expr* e, ptr_vector& sorts) { diff --git a/src/ast/rewriter/var_subst.h b/src/ast/rewriter/var_subst.h index b6a25cfdb..ff0217585 100644 --- a/src/ast/rewriter/var_subst.h +++ b/src/ast/rewriter/var_subst.h @@ -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. diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index f78cd9121..b300b9ac3 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -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(); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 6dd7fbcaa..1950e35f9 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -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; diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index ff39907da..dc3880674 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -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"); diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index 3d2947b7a..8ca36dfc9 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -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. diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 64eeac42e..18c29b97b 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -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", "", "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; } diff --git a/src/model/func_interp.cpp b/src/model/func_interp.cpp index 2eb687dae..38eb4b00b 100644 --- a/src/model/func_interp.cpp +++ b/src/model/func_interp.cpp @@ -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::iterator it = m_entries.begin(); - ptr_vector::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::const_iterator it = m_entries.begin(); - ptr_vector::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 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::const_iterator it = m_entries.begin(); - ptr_vector::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::const_iterator it = m_entries.begin(); - ptr_vector::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 num_occs; expr * r_max = nullptr; unsigned max = 0; - ptr_vector::const_iterator it = m_entries.begin(); - ptr_vector::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 vars; - ptr_vector::const_iterator it = m_entries.begin(); - ptr_vector::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::const_iterator it = m_entries.begin(); - ptr_vector::const_iterator end = m_entries.end(); - for (; it != end; ++it) { - func_entry * curr = *it; + for (func_entry * curr : m_entries) { ptr_buffer new_args; - for (unsigned i=0; iget_arg(i))); new_fi->insert_new_entry(new_args.c_ptr(), translator(curr->get_result())); } diff --git a/src/model/func_interp.h b/src/model/func_interp.h index e2b98d6ea..543124793 100644 --- a/src/model/func_interp.h +++ b/src/model/func_interp.h @@ -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::const_iterator begin() const { return m_entries.begin(); } + ptr_vector::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 & args); + bool is_identity() const; }; #endif diff --git a/src/model/model.cpp b/src/model/model.cpp index 6ddf9765c..97a2917b7 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -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 const & model::get_universe(sort * s) const { ptr_vector * 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 * new_u = alloc(ptr_vector); 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 * 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 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 { + th_rewriter m_rewrite; + obj_map 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 subs; + ptr_buffer 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 cache; + expr_ref_vector trail(m); + ptr_buffer todo; + ptr_buffer 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 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 & 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) { diff --git a/src/model/model.h b/src/model/model.h index cfc44a8fc..0b74de771 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -30,12 +30,28 @@ typedef ref model_ref; class model : public model_core { protected: typedef obj_map*> sort2universe; + typedef obj_hashtable func_decl_set; ptr_vector 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 & 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_ */ diff --git a/src/model/model2expr.cpp b/src/model/model2expr.cpp index 990f9df0f..4ee518282 100644 --- a/src/model/model2expr.cpp +++ b/src/model/model2expr.cpp @@ -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); diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index d41854c22..d92e81421 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -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); } } diff --git a/src/model/model_core.h b/src/model/model_core.h index 3f1e92bad..d705e432d 100644 --- a/src/model/model_core.h +++ b/src/model/model_core.h @@ -27,7 +27,7 @@ class model_core { protected: typedef obj_map decl2expr; typedef obj_map 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 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 diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index f7c7fa74d..0fe1fe7c6 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -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; } diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index bc1900ba7..807e2b4e7 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -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; } diff --git a/src/muz/base/bind_variables.cpp b/src/muz/base/bind_variables.cpp index 2ba7d1473..cbafc57b0 100644 --- a/src/muz/base/bind_variables.cpp +++ b/src/muz/base/bind_variables.cpp @@ -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(); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 220b2516d..d851ec586 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -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 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(); } } diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index dd6728486..d709209e1 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -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 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); diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 2537adbb0..102427a4a 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -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) { } diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index acd200d44..28abbba41 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -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 * rules = it->m_value; - ptr_vector::iterator it2 = rules->begin(); - ptr_vector::iterator end2 = rules->end(); - for (; it2 != end2; ++it2) { - populate(*it2); + for (auto & kv : rules.m_head2rules) { + ptr_vector * 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 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::iterator rit = to_remove.begin(); - ptr_vector::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::iterator it = other.m_orig2pred.begin(); - obj_map::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::iterator it = other.m_pred2orig.begin(); - obj_map::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<get_name()<<" -> "<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<get_name()<<" -> " <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_indexbegin(); - 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"; } diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 6c52d0537..fdafea924 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -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]; diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 97432f544..5f69e4c37 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -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 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 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); diff --git a/src/muz/clp/clp_context.cpp b/src/muz/clp/clp_context.cpp index 8ed017214..f6ebfbfb4 100644 --- a/src/muz/clp/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -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) { diff --git a/src/muz/rel/check_relation.cpp b/src/muz/rel/check_relation.cpp index bd8fb4778..3602db6d9 100644 --- a/src/muz/rel/check_relation.cpp +++ b/src/muz/rel/check_relation.cpp @@ -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); } } diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 2de0679a5..e4b20d250 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -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) diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 030fc1327..fb80a2105 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -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,11 +1408,10 @@ 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(); - + scoped_ptr filter = rmgr.mk_filter_interpreted_fn(*new_rel, to_app(inner_cond)); (*filter)(*new_rel); diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp index 1a1a47f74..f69c1adc1 100644 --- a/src/muz/rel/dl_mk_explanations.cpp +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -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); } }; diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index ac3d30e9e..433c2ced4 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -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); diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index ff12e66c9..89f7fdda3 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -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); diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp index a5ad20059..c4c8959ef 100644 --- a/src/muz/rel/dl_sieve_relation.cpp +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -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) { diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index acfee574a..40569295b 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -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 (); diff --git a/src/muz/spacer/spacer_iuc_proof.h b/src/muz/spacer/spacer_iuc_proof.h index ed36dbf5b..538ab4ff2 100644 --- a/src/muz/spacer/spacer_iuc_proof.h +++ b/src/muz/spacer/spacer_iuc_proof.h @@ -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); diff --git a/src/muz/spacer/spacer_iuc_solver.cpp b/src/muz/spacer/spacer_iuc_solver.cpp index 27b8ee357..a68db4c0a 100644 --- a/src/muz/spacer/spacer_iuc_solver.cpp +++ b/src/muz/spacer/spacer_iuc_solver.cpp @@ -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; diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index aaa203c5e..146434c0a 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -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()); } } diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 7200b3522..c60c770bf 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -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, diff --git a/src/muz/transforms/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp index 670a65e21..06eea7fce 100644 --- a/src/muz/transforms/dl_mk_coalesce.cpp +++ b/src/muz/transforms/dl_mk_coalesce.cpp @@ -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); diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 9f6302e05..058d9dca8 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -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*>::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()); diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 9ceaeeab3..978a22eda 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -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); } diff --git a/src/muz/transforms/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp index 8f3d5c220..6e6f7dd43 100644 --- a/src/muz/transforms/dl_mk_slice.cpp +++ b/src/muz/transforms/dl_mk_slice.cpp @@ -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); diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 1b44b578b..dc4451b6c 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -449,7 +449,6 @@ namespace opt { } lbool r = maxsmt(); if (r == l_true) { - ast_manager& m = m_solver->get_manager(); svector labels; maxsmt.get_model(m_model, labels); // TBD: is m_fm applied or not? diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 016c6f4e5..79ad717c0 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -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); } @@ -1804,7 +1806,7 @@ namespace smt2 { new (mem) app_frame(f, expr_spos, param_spos, has_as); m_num_expr_frames++; } - + void push_expr_frame(expr_frame * curr) { SASSERT(curr_is_lparen()); next(); @@ -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 (( )*) ) expected"); throw parser_exception("invalid quantified expression, syntax error: (forall|exists (( )*) ) 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"), diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 3916e547c..1b6639e8b 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -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; diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 3b8d41316..494773f5d 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -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::iterator it2 = x_cost_vector.begin(); - svector::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::iterator it2 = x_cost_vector.begin(); - svector::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 & v2cs) { - vector::iterator it = v2cs.begin(); - vector::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) { diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 2f44983ff..a0e16727e 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -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(); } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index a2e8fd8b1..68fd56cdf 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -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)); diff --git a/src/smt/cached_var_subst.cpp b/src/smt/cached_var_subst.cpp index 1f184c39c..e096e00a3 100644 --- a/src/smt/cached_var_subst.cpp +++ b/src/smt/cached_var_subst.cpp @@ -63,7 +63,7 @@ void cached_var_subst::operator()(quantifier * qa, unsigned num_bindings, smt::e SASSERT(entry->get_data().m_value == 0); try { - m_proc(qa->get_expr(), new_key->m_num_bindings, new_key->m_bindings, result); + result = m_proc(qa->get_expr(), new_key->m_num_bindings, new_key->m_bindings); } catch (...) { // CMW: The var_subst reducer was interrupted and m_instances is diff --git a/src/smt/fingerprints.cpp b/src/smt/fingerprints.cpp index 832f539df..b9d4571da 100644 --- a/src/smt/fingerprints.cpp +++ b/src/smt/fingerprints.cpp @@ -20,9 +20,10 @@ Revision History: namespace smt { - fingerprint::fingerprint(region & r, void * d, unsigned d_h, unsigned n, enode * const * args): + fingerprint::fingerprint(region & r, void * d, unsigned d_h, expr* def, unsigned n, enode * const * args): m_data(d), m_data_hash(d_h), + m_def(def), m_num_args(n), m_args(nullptr) { m_args = new (r) enode*[n]; @@ -50,8 +51,18 @@ namespace smt { m_dummy.m_args = m_tmp.c_ptr(); return &m_dummy; } + + std::ostream& operator<<(std::ostream& out, fingerprint const& f) { + out << f.get_data_hash() << " " << " num_args " << f.get_num_args() << " "; + for (enode const * arg : f) { + out << " " << arg->get_owner_id(); + } + out << "\n"; + return out; + } + - fingerprint * fingerprint_set::insert(void * data, unsigned data_hash, unsigned num_args, enode * const * args) { + fingerprint * fingerprint_set::insert(void * data, unsigned data_hash, unsigned num_args, enode * const * args, expr* def) { fingerprint * d = mk_dummy(data, data_hash, num_args, args); if (m_set.contains(d)) return nullptr; @@ -66,11 +77,10 @@ namespace smt { tout << "\n";); return nullptr; } - TRACE("fingerprint_bug", tout << "2) inserting: " << data_hash << " num_args: " << num_args; - for (unsigned i = 0; i < num_args; i++) tout << " " << args[i]->get_owner_id(); - tout << "\n";); - fingerprint * f = new (m_region) fingerprint(m_region, data, data_hash, num_args, d->m_args); + TRACE("fingerprint_bug", tout << "2) inserting: " << *d;); + fingerprint * f = new (m_region) fingerprint(m_region, data, data_hash, def, num_args, d->m_args); m_fingerprints.push_back(f); + m_defs.push_back(def); m_set.insert(f); return f; } @@ -89,6 +99,7 @@ namespace smt { void fingerprint_set::reset() { m_set.reset(); m_fingerprints.reset(); + m_defs.reset(); } void fingerprint_set::push_scope() { @@ -104,20 +115,15 @@ namespace smt { for (unsigned i = old_size; i < size; i++) m_set.erase(m_fingerprints[i]); m_fingerprints.shrink(old_size); + m_defs.shrink(old_size); m_scopes.shrink(new_lvl); } void fingerprint_set::display(std::ostream & out) const { out << "fingerprints:\n"; SASSERT(m_set.size() == m_fingerprints.size()); - ptr_vector::const_iterator it = m_fingerprints.begin(); - ptr_vector::const_iterator end = m_fingerprints.end(); - for (; it != end; ++it) { - fingerprint const * f = *it; - out << f->get_data() << " #" << f->get_data_hash(); - for (unsigned i = 0; i < f->get_num_args(); i++) - out << " #" << f->get_arg(i)->get_owner_id(); - out << "\n"; + for (fingerprint const * f : m_fingerprints) { + out << f->get_data() << " " << *f; } } @@ -126,10 +132,7 @@ namespace smt { \brief Slow function for checking if there is a fingerprint congruent to (data args[0] ... args[num_args-1]) */ bool fingerprint_set::slow_contains(void const * data, unsigned data_hash, unsigned num_args, enode * const * args) const { - ptr_vector::const_iterator it = m_fingerprints.begin(); - ptr_vector::const_iterator end = m_fingerprints.end(); - for (; it != end; ++it) { - fingerprint const * f = *it; + for (fingerprint const* f : m_fingerprints) { if (f->get_data() != data) continue; if (f->get_num_args() != num_args) @@ -139,12 +142,7 @@ namespace smt { if (f->get_arg(i)->get_root() != args[i]->get_root()) break; if (i == num_args) { - TRACE("missing_instance_detail", tout << "found instance data: " << data << "=" << f->get_data() << " hash: " << f->get_data_hash(); - for (unsigned i = 0; i < num_args; i++) { - tout << " " << f->get_arg(i)->get_owner_id() << ":" << f->get_arg(i)->get_root()->get_owner_id() << "=" - << args[i]->get_owner_id() << ":" << args[i]->get_root()->get_owner_id(); - } - tout << "\n";); + TRACE("missing_instance_detail", tout << "found instance data: " << data << "=" << *f;); return true; } } diff --git a/src/smt/fingerprints.h b/src/smt/fingerprints.h index fc3259ca7..a5b993470 100644 --- a/src/smt/fingerprints.h +++ b/src/smt/fingerprints.h @@ -20,6 +20,7 @@ Revision History: #define FINGERPRINTS_H_ #include "smt/smt_enode.h" +#include "util/util.h" namespace smt { @@ -27,18 +28,23 @@ namespace smt { protected: void * m_data; unsigned m_data_hash; + expr* m_def; unsigned m_num_args; enode * * m_args; friend class fingerprint_set; fingerprint() {} public: - fingerprint(region & r, void * d, unsigned d_hash, unsigned n, enode * const * args); + fingerprint(region & r, void * d, unsigned d_hash, expr* def, unsigned n, enode * const * args); void * get_data() const { return m_data; } + expr * get_def() const { return m_def; } unsigned get_data_hash() const { return m_data_hash; } unsigned get_num_args() const { return m_num_args; } enode * const * get_args() const { return m_args; } enode * get_arg(unsigned idx) const { SASSERT(idx < m_num_args); return m_args[idx]; } + enode * const * begin() const { return m_args; } + enode * const * end() const { return begin() + get_num_args(); } + friend std::ostream& operator<<(std::ostream& out, fingerprint const& f); }; class fingerprint_set { @@ -60,6 +66,7 @@ namespace smt { region & m_region; set m_set; ptr_vector m_fingerprints; + expr_ref_vector m_defs; unsigned_vector m_scopes; ptr_vector m_tmp; fingerprint m_dummy; @@ -67,8 +74,8 @@ namespace smt { fingerprint * mk_dummy(void * data, unsigned data_hash, unsigned num_args, enode * const * args); public: - fingerprint_set(region & r):m_region(r) {} - fingerprint * insert(void * data, unsigned data_hash, unsigned num_args, enode * const * args); + fingerprint_set(ast_manager& m, region & r): m_region(r), m_defs(m) {} + fingerprint * insert(void * data, unsigned data_hash, unsigned num_args, enode * const * args, expr* def); unsigned size() const { return m_fingerprints.size(); } bool contains(void * data, unsigned data_hash, unsigned num_args, enode * const * args); void reset(); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index c35a0b180..e2a9cbed4 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -16,15 +16,16 @@ Author: Revision History: --*/ -#include "smt/mam.h" -#include "smt/smt_context.h" +#include + #include "util/pool.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" #include "util/trail.h" #include "util/stopwatch.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include "ast/ast_smt2_pp.h" -#include +#include "smt/mam.h" +#include "smt/smt_context.h" // #define _PROFILE_MAM @@ -569,9 +570,8 @@ namespace smt { if (m_context) { ast_manager & m = m_context->get_manager(); out << "patterns:\n"; - for (expr* p : m_patterns) { - out << mk_pp(p, m) << "\n"; - } + for (app* a : m_patterns) + out << mk_pp(a, m) << "\n"; } #endif out << "function: " << m_root_lbl->get_name(); @@ -1482,8 +1482,8 @@ namespace smt { } if (num_instr > SIMPLE_SEQ_THRESHOLD || (curr != nullptr && curr->m_opcode == CHOOSE)) simple = false; - for (unsigned reg : m_to_reset) - m_registers[reg] = 0; + for (unsigned r : m_to_reset) + m_registers[r] = 0; return weight; } @@ -1998,19 +1998,19 @@ namespace smt { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); if (t->filter_candidates()) { - for (enode * app : t->get_candidates()) { + for (enode* app : t->get_candidates()) { if (!app->is_marked() && app->is_cgr()) { execute_core(t, app); app->set_mark(); } } - for (enode * app : t->get_candidates()) { + for (enode* app : t->get_candidates()) { if (app->is_marked()) app->unset_mark(); } } else { - for (enode * app : t->get_candidates()) { + for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (app->is_cgr()) { TRACE("trigger_bug", tout << "is_cgr\n";); @@ -2797,7 +2797,7 @@ namespace smt { void display_trees(std::ostream & out, const ptr_vector & trees) { unsigned lbl = 0; - for (code_tree* tree : trees) { + for (code_tree * tree : trees) { if (tree) { out << "tree for f" << lbl << "\n"; out << *tree; @@ -3143,10 +3143,7 @@ namespace smt { m_trail_stack.push(set_bitvector_trail(m_is_clbl, lbl_id)); SASSERT(m_is_clbl[lbl_id]); unsigned h = m_lbl_hasher(lbl); - enode_vector::const_iterator it = m_context.begin_enodes_of(lbl); - enode_vector::const_iterator end = m_context.end_enodes_of(lbl); - for (; it != end; ++it) { - enode * app = *it; + for (enode* app : m_context.enodes_of(lbl)) { if (m_context.is_relevant(app)) { update_lbls(app, h); TRACE("mam_bug", tout << "updating labels of: #" << app->get_owner_id() << "\n"; @@ -3188,10 +3185,7 @@ namespace smt { SASSERT(m_is_plbl[lbl_id]); SASSERT(is_plbl(lbl)); unsigned h = m_lbl_hasher(lbl); - enode_vector::const_iterator it = m_context.begin_enodes_of(lbl); - enode_vector::const_iterator end = m_context.end_enodes_of(lbl); - for (; it != end; ++it) { - enode * app = *it; + for (enode * app : m_context.enodes_of(lbl)) { if (m_context.is_relevant(app)) update_children_plbls(app, h); } @@ -3677,18 +3671,12 @@ namespace smt { approx_set & plbls = r1->get_plbls(); approx_set & clbls = r2->get_lbls(); if (!plbls.empty() && !clbls.empty()) { - approx_set::iterator it1 = plbls.begin(); - approx_set::iterator end1 = plbls.end(); - for (; it1 != end1; ++it1) { + for (unsigned plbl1 : plbls) { if (m_context.get_cancel_flag()) { break; } - unsigned plbl1 = *it1; SASSERT(plbls.may_contain(plbl1)); - approx_set::iterator it2 = clbls.begin(); - approx_set::iterator end2 = clbls.end(); - for (; it2 != end2; ++it2) { - unsigned lbl2 = *it2; + for (unsigned lbl2 : clbls) { SASSERT(clbls.may_contain(lbl2)); collect_parents(r1, m_pc[plbl1][lbl2]); } @@ -3699,14 +3687,12 @@ namespace smt { void match_new_patterns() { TRACE("mam_new_pat", tout << "matching new patterns:\n";); m_tmp_trees_to_delete.reset(); - svector::iterator it1 = m_new_patterns.begin(); - svector::iterator end1 = m_new_patterns.end(); - for (; it1 != end1; ++it1) { + for (auto const& kv : m_new_patterns) { if (m_context.get_cancel_flag()) { break; } - quantifier * qa = it1->first; - app * mp = it1->second; + quantifier * qa = kv.first; + app * mp = kv.second; SASSERT(m_ast_manager.is_pattern(mp)); app * p = to_app(mp->get_arg(0)); func_decl * lbl = p->get_decl(); @@ -3723,19 +3709,13 @@ namespace smt { } } - ptr_vector::iterator it2 = m_tmp_trees_to_delete.begin(); - ptr_vector::iterator end2 = m_tmp_trees_to_delete.end(); - for (; it2 != end2; ++it2) { - func_decl * lbl = *it2; + for (func_decl * lbl : m_tmp_trees_to_delete) { unsigned lbl_id = lbl->get_decl_id(); code_tree * tmp_tree = m_tmp_trees[lbl_id]; SASSERT(tmp_tree != 0); SASSERT(m_context.get_num_enodes_of(lbl) > 0); m_interpreter.init(tmp_tree); - enode_vector::const_iterator it3 = m_context.begin_enodes_of(lbl); - enode_vector::const_iterator end3 = m_context.end_enodes_of(lbl); - for (; it3 != end3; ++it3) { - enode * app = *it3; + for (enode * app : m_context.enodes_of(lbl)) { if (m_context.is_relevant(app)) m_interpreter.execute_core(tmp_tree, app); } @@ -3824,10 +3804,7 @@ namespace smt { void pop_scope(unsigned num_scopes) override { if (!m_to_match.empty()) { - ptr_vector::iterator it = m_to_match.begin(); - ptr_vector::iterator end = m_to_match.end(); - for (; it != end; ++it) { - code_tree * t = *it; + for (code_tree* t : m_to_match) { t->reset_candidates(); } m_to_match.reset(); @@ -3860,10 +3837,7 @@ namespace smt { void match() override { TRACE("trigger_bug", tout << "match\n"; display(tout);); - ptr_vector::iterator it = m_to_match.begin(); - ptr_vector::iterator end = m_to_match.end(); - for (; it != end; ++it) { - code_tree * t = *it; + for (code_tree* t : m_to_match) { SASSERT(t->has_candidates()); m_interpreter.execute(t); t->reset_candidates(); @@ -3884,10 +3858,7 @@ namespace smt { if (t) { m_interpreter.init(t); func_decl * lbl = t->get_root_lbl(); - enode_vector::const_iterator it2 = m_context.begin_enodes_of(lbl); - enode_vector::const_iterator end2 = m_context.end_enodes_of(lbl); - for (; it2 != end2; ++it2) { - enode * curr = *it2; + for (enode * curr : m_context.enodes_of(lbl)) { if (use_irrelevant || m_context.is_relevant(curr)) m_interpreter.execute_core(t, curr); } @@ -3924,7 +3895,7 @@ namespace smt { #endif unsigned min_gen, max_gen; m_interpreter.get_min_max_top_generation(min_gen, max_gen); - m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, min_gen, max_gen, used_enodes); + m_context.add_instance(qa, pat, num_bindings, bindings, nullptr, max_generation, min_gen, max_gen, used_enodes); } bool is_shared(enode * n) const override { diff --git a/src/smt/params/theory_array_params.h b/src/smt/params/theory_array_params.h index edda4d7cf..a3be083d7 100644 --- a/src/smt/params/theory_array_params.h +++ b/src/smt/params/theory_array_params.h @@ -40,6 +40,7 @@ struct theory_array_params { bool m_array_always_prop_upward; bool m_array_lazy_ieq; unsigned m_array_lazy_ieq_delay; + bool m_array_fake_support; // fake support for all array operations to pretend they are satisfiable. theory_array_params(): m_array_canonize_simplify(false), @@ -52,7 +53,8 @@ struct theory_array_params { m_array_cg(false), m_array_always_prop_upward(true), // UPWARDs filter is broken... TODO: fix it m_array_lazy_ieq(false), - m_array_lazy_ieq_delay(10) { + m_array_lazy_ieq_delay(10), + m_array_fake_support(false) { } diff --git a/src/smt/proto_model/array_factory.cpp b/src/smt/proto_model/array_factory.cpp index 919f18dc0..dc3e0f89c 100644 --- a/src/smt/proto_model/array_factory.cpp +++ b/src/smt/proto_model/array_factory.cpp @@ -17,11 +17,11 @@ Revision History: --*/ -#include "smt/proto_model/array_factory.h" #include "ast/array_decl_plugin.h" -#include "smt/proto_model/proto_model.h" -#include "model/func_interp.h" #include "ast/ast_pp.h" +#include "model/func_interp.h" +#include "smt/proto_model/array_factory.h" +#include "smt/proto_model/proto_model.h" func_decl * mk_aux_decl_for_array_sort(ast_manager & m, sort * s) { ptr_buffer domain; @@ -67,9 +67,13 @@ expr * array_factory::get_some_value(sort * s) { return *(set->begin()); func_interp * fi; expr * val = mk_array_interp(s, fi); +#if 0 ptr_buffer args; get_some_args_for(s, args); fi->insert_entry(args.c_ptr(), m_model.get_some_value(get_array_range(s))); +#else + fi->set_else(m_model.get_some_value(get_array_range(s))); +#endif return val; } @@ -143,9 +147,13 @@ expr * array_factory::get_fresh_value(sort * s) { // easy case func_interp * fi; expr * val = mk_array_interp(s, fi); +#if 0 ptr_buffer args; get_some_args_for(s, args); fi->insert_entry(args.c_ptr(), range_val); +#else + fi->set_else(range_val); +#endif return val; } else { diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 8af3af277..654925f72 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -18,13 +18,15 @@ Revision History: --*/ #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" -#include "ast/rewriter/var_subst.h" #include "ast/well_sorted.h" #include "ast/used_symbols.h" +#include "ast/for_each_expr.h" +#include "ast/rewriter/var_subst.h" #include "model/model_params.hpp" #include "model/model_v2_pp.h" #include "smt/proto_model/proto_model.h" + proto_model::proto_model(ast_manager & m, params_ref const & p): model_core(m), m_eval(*this), @@ -75,7 +77,7 @@ expr * proto_model::mk_some_interp_for(func_decl * d) { register_decl(d, r); } else { - func_interp * new_fi = alloc(func_interp, m_manager, d->get_arity()); + func_interp * new_fi = alloc(func_interp, m, d->get_arity()); new_fi->set_else(r); register_decl(d, new_fi); } @@ -86,6 +88,7 @@ expr * proto_model::mk_some_interp_for(func_decl * d) { bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) { m_eval.set_model_completion(model_completion); m_eval.set_expand_array_equalities(false); + TRACE("model_evaluator", model_v2_pp(tout, *this, true);); try { m_eval(e, result); return true; @@ -120,10 +123,10 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au if (fi->is_partial()) return; expr * fi_else = fi->get_else(); - TRACE("model_bug", tout << "cleaning up:\n" << mk_pp(fi_else, m_manager) << "\n";); + TRACE("model_bug", tout << "cleaning up:\n" << mk_pp(fi_else, m) << "\n";); obj_map cache; - expr_ref_vector trail(m_manager); + expr_ref_vector trail(m); ptr_buffer todo; ptr_buffer args; todo.push_back(fi_else); @@ -165,7 +168,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au TRACE("model_bug", tout << f->get_name() << "\n";); found_aux_fs.insert(f); } - expr_ref new_t(m_manager); + expr_ref new_t(m); new_t = m_rewrite.mk_app(f, args.size(), args.c_ptr()); if (t != new_t.get()) trail.push_back(new_t); @@ -235,7 +238,7 @@ value_factory * proto_model::get_factory(family_id fid) { } void proto_model::freeze_universe(sort * s) { - SASSERT(m_manager.is_uninterp(s)); + SASSERT(m.is_uninterp(s)); m_user_sort_factory->freeze_universe(s); } @@ -270,11 +273,11 @@ sort * proto_model::get_uninterpreted_sort(unsigned idx) const { in the model. */ bool proto_model::is_finite(sort * s) const { - return m_manager.is_uninterp(s) && m_user_sort_factory->is_finite(s); + return m.is_uninterp(s) && m_user_sort_factory->is_finite(s); } expr * proto_model::get_some_value(sort * s) { - if (m_manager.is_uninterp(s)) { + if (m.is_uninterp(s)) { return m_user_sort_factory->get_some_value(s); } else { @@ -288,7 +291,7 @@ expr * proto_model::get_some_value(sort * s) { } bool proto_model::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { - if (m_manager.is_uninterp(s)) { + if (m.is_uninterp(s)) { return m_user_sort_factory->get_some_values(s, v1, v2); } else { @@ -302,7 +305,7 @@ bool proto_model::get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { } expr * proto_model::get_fresh_value(sort * s) { - if (m_manager.is_uninterp(s)) { + if (m.is_uninterp(s)) { return m_user_sort_factory->get_fresh_value(s); } else { @@ -318,8 +321,8 @@ expr * proto_model::get_fresh_value(sort * s) { } void proto_model::register_value(expr * n) { - sort * s = m_manager.get_sort(n); - if (m_manager.is_uninterp(s)) { + sort * s = m.get_sort(n); + if (m.is_uninterp(s)) { m_user_sort_factory->register_value(n); } else { @@ -374,15 +377,15 @@ void proto_model::complete_partial_funcs(bool use_fresh) { model * proto_model::mk_model() { TRACE("proto_model", model_v2_pp(tout << "mk_model\n", *this);); - model * m = alloc(model, m_manager); + model * mdl = alloc(model, m); for (auto const& kv : m_interp) { - m->register_decl(kv.m_key, kv.m_value); + mdl->register_decl(kv.m_key, kv.m_value); } for (auto const& kv : m_finterp) { - m->register_decl(kv.m_key, kv.m_value); - m_manager.dec_ref(kv.m_key); + mdl->register_decl(kv.m_key, kv.m_value); + m.dec_ref(kv.m_key); } m_finterp.reset(); // m took the ownership of the func_interp's @@ -390,10 +393,11 @@ model * proto_model::mk_model() { unsigned sz = get_num_uninterpreted_sorts(); for (unsigned i = 0; i < sz; i++) { sort * s = get_uninterpreted_sort(i); - TRACE("proto_model", tout << "copying uninterpreted sorts...\n" << mk_pp(s, m_manager) << "\n";); + TRACE("proto_model", tout << "copying uninterpreted sorts...\n" << mk_pp(s, m) << "\n";); ptr_vector const& buf = get_universe(s); - m->register_usort(s, buf.size(), buf.c_ptr()); + mdl->register_usort(s, buf.size(), buf.c_ptr()); } - return m; + return mdl; } + diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h index 04e3a90fe..b9ed65fb1 100644 --- a/src/smt/proto_model/proto_model.h +++ b/src/smt/proto_model/proto_model.h @@ -38,6 +38,7 @@ Revision History: #include "util/params.h" #include "ast/rewriter/th_rewriter.h" + class proto_model : public model_core { plugin_manager m_factories; user_sort_factory * m_user_sort_factory; diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 4e639a7b2..94868ef6e 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -148,7 +148,7 @@ namespace smt { } void qi_queue::instantiate() { - unsigned since_last_check = 0; + unsigned since_last_check = 0; for (entry & curr : m_new_entries) { fingerprint * f = curr.m_qb; quantifier * qa = static_cast(f->get_data()); @@ -169,7 +169,6 @@ namespace smt { // Periodically check if we didn't run out of time/memory. if (since_last_check++ > 100) { if (m_context.resource_limits_exceeded()) { - // verbose_stream() << "EXCEEDED...\n"; break; } since_last_check = 0; @@ -182,16 +181,7 @@ namespace smt { void qi_queue::display_instance_profile(fingerprint * f, quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned proof_id, unsigned generation) { if (m_manager.has_trace_stream()) { m_manager.trace_stream() << "[instance] "; -#if 1 m_manager.trace_stream() << static_cast(f); -#else - for (unsigned i = 0; i < num_bindings; i++) { - // I don't want to use mk_pp because it creates expressions for pretty printing. - // This nasty side-effect may change the behavior of Z3. - m_manager.trace_stream() << " #" << bindings[i]->get_owner_id(); - } - -#endif if (m_manager.proofs_enabled()) m_manager.trace_stream() << " #" << proof_id; m_manager.trace_stream() << " ; " << generation; @@ -208,10 +198,7 @@ namespace smt { ent.m_instantiated = true; - TRACE("qi_queue_profile", - tout << q->get_qid() << ", gen: " << generation; - for (unsigned i = 0; i < num_bindings; i++) tout << " #" << bindings[i]->get_owner_id(); - tout << "\n";); + TRACE("qi_queue_profile", tout << q->get_qid() << ", gen: " << generation << " " << *f;); if (m_checker.is_sat(q->get_expr(), num_bindings, bindings)) { TRACE("checker", tout << "instance already satisfied\n";); @@ -288,6 +275,9 @@ namespace smt { unsigned gen = get_new_gen(q, generation, ent.m_cost); display_instance_profile(f, q, num_bindings, bindings, proof_id, gen); m_context.internalize_instance(lemma, pr1, gen); + if (f->get_def()) { + m_context.internalize(f->get_def(), true); + } TRACE_CODE({ static unsigned num_useless = 0; if (m_manager.is_or(lemma)) { @@ -412,10 +402,7 @@ namespace smt { void qi_queue::display_delayed_instances_stats(std::ostream & out) const { obj_map qa2info; ptr_vector qas; - svector::const_iterator it = m_delayed_entries.begin(); - svector::const_iterator end = m_delayed_entries.end(); - for (; it != end; ++it) { - entry const & e = *it; + for (entry const & e : m_delayed_entries) { if (e.m_instantiated) continue; quantifier * qa = static_cast(e.m_qb->get_data()); @@ -433,10 +420,7 @@ namespace smt { } qa2info.insert(qa, info); } - ptr_vector::iterator it2 = qas.begin(); - ptr_vector::iterator end2 = qas.end(); - for (; it2 != end2; ++it2) { - quantifier * qa = *it2; + for (quantifier * qa : qas) { delayed_qa_info info; qa2info.find(qa, info); out << qa->get_qid() << ": " << info.m_num << " [" << info.m_min_cost << ", " << info.m_max_cost << "]\n"; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 48033f9b5..fd9b27069 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -53,7 +53,7 @@ namespace smt { m_flushing(false), m_progress_callback(nullptr), m_next_progress_sample(0), - m_fingerprints(m_region), + m_fingerprints(m, m_region), m_b_internalized_stack(m), m_e_internalized_stack(m), m_final_check_idx(0), @@ -1785,9 +1785,9 @@ namespace smt { return m_fingerprints.contains(q, q->get_id(), num_bindings, bindings); } - bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, + bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, expr* def, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes) { - return m_qmanager->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_top_generation, used_enodes); + return m_qmanager->add_instance(q, pat, num_bindings, bindings, def, max_generation, min_top_generation, max_top_generation, used_enodes); } void context::rescale_bool_var_activity() { @@ -2932,7 +2932,7 @@ namespace smt { void context::assert_expr_core(expr * e, proof * pr) { if (get_cancel_flag()) return; SASSERT(is_well_sorted(m_manager, e)); - TRACE("begin_assert_expr", tout << mk_pp(e, m_manager) << "\n";); + TRACE("begin_assert_expr", tout << this << " " << mk_pp(e, m_manager) << "\n";); TRACE("begin_assert_expr_ll", tout << mk_ll_pp(e, m_manager) << "\n";); pop_to_base_lvl(); if (pr == nullptr) @@ -4401,9 +4401,9 @@ namespace smt { for (unsigned i = 0; !get_cancel_flag() && i < m_asserted_formulas.get_num_formulas(); ++i) { expr* e = m_asserted_formulas.get_formula(i); if (is_quantifier(e)) { - TRACE("context", tout << mk_pp(e, m) << "\n";); quantifier* q = to_quantifier(e); if (!m.is_rec_fun_def(q)) continue; + TRACE("context", tout << mk_pp(e, m) << "\n";); SASSERT(q->get_num_patterns() == 2); expr* fn = to_app(q->get_pattern(0))->get_arg(0); expr* body = to_app(q->get_pattern(1))->get_arg(0); @@ -4417,7 +4417,7 @@ namespace smt { expr_ref bodyr(m); var_subst sub(m, true); TRACE("context", tout << expr_ref(q, m) << " " << subst << "\n";); - sub(body, subst.size(), subst.c_ptr(), bodyr); + bodyr = sub(body, subst.size(), subst.c_ptr()); func_decl* f = to_app(fn)->get_decl(); func_interp* fi = alloc(func_interp, m, f->get_arity()); fi->set_else(bodyr); diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index e85348a07..48b689bd7 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -116,6 +116,7 @@ namespace smt { plugin_manager m_theories; // mapping from theory_id -> theory ptr_vector m_theory_set; // set of theories for fast traversal vector m_decl2enodes; // decl -> enode (for decls with arity > 0) + enode_vector m_empty_vector; cg_table m_cg_table; dyn_ack_manager m_dyn_ack_manager; struct new_eq { @@ -456,6 +457,8 @@ namespace smt { theory * get_theory(theory_id th_id) const { return m_theories.get_plugin(th_id); } + + ptr_vector const& theories() const { return m_theories.plugins(); } ptr_vector::const_iterator begin_theories() const { return m_theories.begin(); @@ -517,6 +520,11 @@ namespace smt { return id < m_decl2enodes.size() ? m_decl2enodes[id].size() : 0; } + enode_vector const& enodes_of(func_decl const * d) const { + unsigned id = d->get_decl_id(); + return id < m_decl2enodes.size() ? m_decl2enodes[id] : m_empty_vector; + } + enode_vector::const_iterator begin_enodes_of(func_decl const * decl) const { unsigned id = decl->get_decl_id(); return id < m_decl2enodes.size() ? m_decl2enodes[id].begin() : nullptr; @@ -527,6 +535,8 @@ namespace smt { return id < m_decl2enodes.size() ? m_decl2enodes[id].end() : nullptr; } + ptr_vector const& enodes() const { return m_enodes; } + ptr_vector::const_iterator begin_enodes() const { return m_enodes.begin(); } @@ -553,8 +563,8 @@ namespace smt { return m_asserted_formulas.has_quantifiers(); } - fingerprint * add_fingerprint(void * data, unsigned data_hash, unsigned num_args, enode * const * args) { - return m_fingerprints.insert(data, data_hash, num_args, args); + fingerprint * add_fingerprint(void * data, unsigned data_hash, unsigned num_args, enode * const * args, expr* def = 0) { + return m_fingerprints.insert(data, data_hash, num_args, args, def); } theory_id get_var_theory(bool_var v) const { @@ -736,6 +746,8 @@ namespace smt { void internalize_quantifier(quantifier * q, bool gate_ctx); + void internalize_lambda(quantifier * q); + void internalize_formula_core(app * n, bool gate_ctx); void set_merge_tf(enode * n, bool_var v, bool is_new_var); @@ -957,7 +969,7 @@ namespace smt { bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); - bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, expr* def, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); void set_global_generation(unsigned generation) { m_generation = generation; } diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index f9ee900ff..d377e5355 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -329,6 +329,9 @@ namespace smt { SASSERT(is_quantifier(n) || is_app(n)); internalize_formula(n, gate_ctx); } + else if (is_lambda(n)) { + internalize_lambda(to_quantifier(n)); + } else { SASSERT(is_app(n)); SASSERT(!gate_ctx); @@ -514,7 +517,7 @@ namespace smt { CTRACE("internalize_quantifier_zero", q->get_weight() == 0, tout << mk_pp(q, m_manager) << "\n";); SASSERT(gate_ctx); // limitation of the current implementation SASSERT(!b_internalized(q)); - SASSERT(q->is_forall()); + SASSERT(is_forall(q)); SASSERT(check_patterns(q)); bool_var v = mk_bool_var(q); unsigned generation = m_generation; @@ -528,6 +531,31 @@ namespace smt { m_qmanager->add(q, generation); } + void context::internalize_lambda(quantifier * q) { + UNREACHABLE(); + +#if 0 + TRACE("internalize_quantifier", tout << mk_pp(q, m_manager) << "\n";); + SASSERT(is_lambda(q)); + app_ref lam_name(m_manager.mk_fresh_const("lambda", m_manager.get_sort(q)), m_manager); + enode * e = mk_enode(lam_name, true, false, false); + expr_ref eq(m_manager), lam_app(m_manager); + expr_ref_vector vars(m_manager); + vars.push_back(lam_name); + unsigned sz = q->get_num_decls(); + for (unsigned i = 0; i < sz; ++i) { + vars.push_back(m_manager.mk_var(sz - i - 1, q->get_decl_sort(i))); + } + array_util autil(m_manager); + lam_app = autil.mk_select(vars.size(), vars.c_ptr()); + eq = m_manager.mk_eq(lam_app, q->get_expr()); + quantifier_ref fa(m_manager); + expr * patterns[1] = { m_manager.mk_pattern(lam_name) }; + fa = m_manager.mk_forall(sz, q->get_decl_sorts(), q->get_decl_names(), eq, 0, m_manager.lambda_def_qid(), symbol::null, 1, patterns); + internalize_quantifier(fa, true); +#endif + } + /** \brief Internalize gates and (uninterpreted and equality) predicates. */ diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 5ab52b57c..06dd04846 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -15,12 +15,19 @@ Author: Revision History: +- to support lambdas/array models: + binding sk -> (as-array k!0) + then include definition for k!0 as part of binding. + Binding instance can be a pointer into m_pinned expressions. + --*/ #include "ast/normal_forms/pull_quant.h" #include "ast/for_each_expr.h" #include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" #include "ast/ast_pp.h" +#include "ast/array_decl_plugin.h" #include "ast/ast_smt2_pp.h" #include "smt/smt_model_checker.h" #include "smt/smt_context.h" @@ -53,8 +60,8 @@ namespace smt { } void model_checker::set_qm(quantifier_manager & qm) { - SASSERT(m_qm == 0); - SASSERT(m_context == 0); + SASSERT(m_qm == nullptr); + SASSERT(m_context == nullptr); m_qm = &qm; m_context = &(m_qm->get_context()); } @@ -63,6 +70,13 @@ namespace smt { \brief Return a term in the context that evaluates to val. */ expr * model_checker::get_term_from_ctx(expr * val) { + init_value2expr(); + expr * t = nullptr; + m_value2expr.find(val, t); + return t; + } + + void model_checker::init_value2expr() { if (m_value2expr.empty()) { // populate m_value2expr for (auto const& kv : *m_root2value) { @@ -72,9 +86,28 @@ namespace smt { m_value2expr.insert(val, n->get_owner()); } } - expr * t = nullptr; - m_value2expr.find(val, t); - return t; + } + + expr_ref model_checker::replace_value_from_ctx(expr * e) { + init_value2expr(); + struct beta_reducer_cfg : default_rewriter_cfg { + model_checker& mc; + beta_reducer_cfg(model_checker& mc):mc(mc) {} + bool get_subst(expr * e, expr* & t, proof *& pr) { + t = nullptr; pr = nullptr; + mc.m_value2expr.find(e, t); + return t != nullptr; + } + }; + struct beta_reducer : public rewriter_tpl { + beta_reducer_cfg m_cfg; + beta_reducer(model_checker& m): + rewriter_tpl(m.m, false, m_cfg), m_cfg(m) {} + }; + beta_reducer br(*this); + expr_ref result(m); + br(e, result); + return result; } /** @@ -94,8 +127,6 @@ namespace smt { m_aux_context->assert_expr(fml); } -#define PP_DEPTH 8 - /** \brief Assert the negation of q after applying the interpretation in m_curr_model to the uninterpreted symbols in q. @@ -122,9 +153,8 @@ namespace smt { } } - expr_ref sk_body(m); var_subst s(m); - s(tmp, subst_args.size(), subst_args.c_ptr(), sk_body); + expr_ref sk_body = s(tmp, subst_args.size(), subst_args.c_ptr()); expr_ref r(m); r = m.mk_not(sk_body); TRACE("model_checker", tout << "mk_neg_q_m:\n" << mk_ismt2_pp(r, m) << "\n";); @@ -132,37 +162,35 @@ namespace smt { } bool model_checker::add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv) { - if (cex == nullptr) { + if (cex == nullptr || sks.empty()) { TRACE("model_checker", tout << "no model is available\n";); return false; } + array_util autil(m); unsigned num_decls = q->get_num_decls(); // Remark: sks were created for the flat version of q. SASSERT(sks.size() >= num_decls); - expr_ref_vector bindings(m); + expr_ref_vector bindings(m), defs(m); + expr_ref def(m); bindings.resize(num_decls); unsigned max_generation = 0; for (unsigned i = 0; i < num_decls; i++) { expr * sk = sks.get(num_decls - i - 1); func_decl * sk_d = to_app(sk)->get_decl(); - expr_ref sk_value(m); - sk_value = cex->get_const_interp(sk_d); - if (sk_value == 0) { - sk_value = cex->get_some_value(sk_d->get_range()); - if (sk_value == 0) { - TRACE("model_checker", tout << "Could not get value for " << sk_d->get_name() << "\n";); - return false; // get_some_value failed... giving up - } - TRACE("model_checker", tout << "Got some value " << sk_value << "\n";); + expr_ref sk_value(cex->get_some_const_interp(sk_d), m); + if (!sk_value) { + TRACE("model_checker", tout << "Could not get value for " << sk_d->get_name() << "\n";); + return false; // get_some_value failed... giving up } + TRACE("model_checker", tout << "Got some value " << sk_value << "\n";); + if (use_inv) { unsigned sk_term_gen; expr * sk_term = m_model_finder.get_inv(q, i, sk_value, sk_term_gen); if (sk_term != nullptr) { TRACE("model_checker", tout << "Found inverse " << mk_pp(sk_term, m) << "\n";); SASSERT(!m.is_model_value(sk_term)); - if (sk_term_gen > max_generation) - max_generation = sk_term_gen; + max_generation = std::max(sk_term_gen, max_generation); sk_value = sk_term; } else { @@ -180,39 +208,48 @@ namespace smt { TRACE("model_checker", tout << "value is private to model: " << sk_value << "\n";); return false; } + func_decl * f = nullptr; + if (autil.is_as_array(sk_value, f) && cex->get_func_interp(f)) { + expr_ref body(cex->get_func_interp(f)->get_interp(), m); + ptr_vector sorts(f->get_arity(), f->get_domain()); + svector names; + for (unsigned i = 0; i < f->get_arity(); ++i) { + names.push_back(symbol(i)); + } + defined_names dn(m); + body = replace_value_from_ctx(body); + body = m.mk_lambda(sorts.size(), sorts.c_ptr(), names.c_ptr(), body); + // sk_value = m.mk_fresh_const(0, m.get_sort(sk_value)); // get rid of as-array + body = dn.mk_definition(body, to_app(sk_value)); + defs.push_back(body); + } bindings.set(num_decls - i - 1, sk_value); } - TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: "; - for (unsigned i = 0; i < num_decls; i++) { - tout << mk_ismt2_pp(bindings[i].get(), m) << " "; - } - tout << "\n";); - + TRACE("model_checker", tout << q->get_qid() << " found (use_inv: " << use_inv << ") new instance: " << bindings << "\n" << defs << "\n";); + if (!defs.empty()) def = mk_and(defs); max_generation = std::max(m_qm->get_generation(q), max_generation); - add_instance(q, bindings, max_generation); + add_instance(q, bindings, max_generation, def.get()); return true; } - void model_checker::add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation) { + void model_checker::add_instance(quantifier* q, expr_ref_vector const& bindings, unsigned max_generation, expr* def) { SASSERT(q->get_num_decls() == bindings.size()); - for (expr* b : bindings) - m_pinned_exprs.push_back(b); + unsigned offset = m_pinned_exprs.size(); + m_pinned_exprs.append(bindings); m_pinned_exprs.push_back(q); - - void * mem = m_new_instances_region.allocate(instance::get_obj_size(q->get_num_decls())); - instance * new_inst = new (mem) instance(q, bindings.c_ptr(), max_generation); - m_new_instances.push_back(new_inst); + m_pinned_exprs.push_back(def); + m_new_instances.push_back(instance(q, offset, def, max_generation)); } void model_checker::operator()(expr *n) { - if (m.is_model_value(n) || m_autil.is_as_array(n)) { + if (m.is_model_value(n) /*|| m_autil.is_as_array(n)*/) { throw is_model_value(); } } bool model_checker::contains_model_value(expr* n) { - if (m.is_model_value(n) || m_autil.is_as_array(n)) { + if (m.is_model_value(n) /*|| m_autil.is_as_array(n)*/) { return true; } if (is_app(n) && to_app(n)->get_num_args() == 0) { @@ -230,16 +267,13 @@ namespace smt { bool model_checker::add_blocking_clause(model * cex, expr_ref_vector & sks) { - SASSERT(cex != 0); + SASSERT(cex != nullptr); expr_ref_buffer diseqs(m); for (expr * sk : sks) { func_decl * sk_d = to_app(sk)->get_decl(); - expr_ref sk_value(m); - sk_value = cex->get_const_interp(sk_d); - if (sk_value == 0) { - sk_value = cex->get_some_value(sk_d->get_range()); - if (sk_value == 0) - return false; // get_some_value failed... aborting add_blocking_clause + expr_ref sk_value(cex->get_some_const_interp(sk_d), m); + if (!sk_value) { + return false; // get_some_value failed... aborting add_blocking_clause } diseqs.push_back(m.mk_not(m.mk_eq(sk, sk_value))); } @@ -250,40 +284,43 @@ namespace smt { return true; } + struct scoped_ctx_push { + context* c; + scoped_ctx_push(context* c): c(c) { c->push(); } + ~scoped_ctx_push() { c->pop(1); } + }; + /** \brief Return true if q is satisfied by m_curr_model. */ bool model_checker::check(quantifier * q) { SASSERT(!m_aux_context->relevancy()); - m_aux_context->push(); + scoped_ctx_push _push(m_aux_context.get()); quantifier * flat_q = get_flat_quantifier(q); - TRACE("model_checker", tout << "model checking:\n" << mk_ismt2_pp(q->get_expr(), m) << "\n" << - mk_ismt2_pp(flat_q->get_expr(), m) << "\n";); + TRACE("model_checker", tout << "model checking:\n" << expr_ref(q->get_expr(), m) << "\n" << expr_ref(flat_q->get_expr(), m) << "\n";); expr_ref_vector sks(m); assert_neg_q_m(flat_q, sks); - TRACE("model_checker", tout << "skolems:\n"; - for (expr* sk : sks) { - tout << mk_ismt2_pp(sk, m) << " " << mk_pp(m.get_sort(sk), m) << "\n"; - }); + TRACE("model_checker", tout << "skolems:\n" << sks << "\n";); + flet l(m_aux_context->get_fparams().m_array_fake_support, true); lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";); - if (r != l_true) { - m_aux_context->pop(1); + if (r != l_true) { return r == l_false; // quantifier is satisfied by m_curr_model } model_ref complete_cex; m_aux_context->get_model(complete_cex); - + // try to find new instances using instantiation sets. m_model_finder.restrict_sks_to_inst_set(m_aux_context.get(), q, sks); - + unsigned num_new_instances = 0; - + while (true) { + flet l(m_aux_context->get_fparams().m_array_fake_support, true); lbool r = m_aux_context->check(); TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";); if (r != l_true) @@ -307,7 +344,6 @@ namespace smt { add_instance(q, complete_cex.get(), sks, false); } - m_aux_context->pop(1); return false; } @@ -317,33 +353,29 @@ namespace smt { expr* fn = to_app(q->get_pattern(0))->get_arg(0); SASSERT(is_app(fn)); func_decl* f = to_app(fn)->get_decl(); - enode_vector::const_iterator it = m_context->begin_enodes_of(f); - enode_vector::const_iterator end = m_context->end_enodes_of(f); - bool is_undef = false; expr_ref_vector args(m); unsigned num_decls = q->get_num_decls(); args.resize(num_decls, nullptr); var_subst sub(m); expr_ref tmp(m), result(m); - for (; it != end; ++it) { - if (m_context->is_relevant(*it)) { - app* e = (*it)->get_owner(); + for (enode* n : m_context->enodes_of(f)) { + if (m_context->is_relevant(n)) { + app* e = n->get_owner(); SASSERT(e->get_num_args() == num_decls); for (unsigned i = 0; i < num_decls; ++i) { args[i] = e->get_arg(i); } - sub(q->get_expr(), num_decls, args.c_ptr(), tmp); + tmp = sub(q->get_expr(), num_decls, args.c_ptr()); m_curr_model->eval(tmp, result, true); if (strict_rec_fun ? !m.is_true(result) : m.is_false(result)) { - add_instance(q, args, 0); + add_instance(q, args, 0, nullptr); return false; } - TRACE("model_checker", tout << tmp << "\nevaluates to:\n" << result << "\n";); - // if (!m.is_true(result)) is_undef = true; + TRACE("model_checker", tout << tmp << "\nevaluates to:\n" << result << "\n";); } } - return !is_undef; + return true; } void model_checker::init_aux_context() { @@ -359,7 +391,7 @@ namespace smt { } bool model_checker::check(proto_model * md, obj_map const & root2value) { - SASSERT(md != 0); + SASSERT(md != nullptr); m_root2value = &root2value; @@ -390,7 +422,6 @@ namespace smt { check_quantifiers(false, found_relevant, num_failures); - if (found_relevant) m_iteration_idx++; @@ -415,35 +446,47 @@ namespace smt { return num_failures == 0; } + // + // (repeated from defined_names.cpp) + // NB. The pattern for lambdas 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. + // + void model_checker::check_quantifiers(bool strict_rec_fun, bool& found_relevant, unsigned& num_failures) { - ptr_vector::const_iterator it = m_qm->begin_quantifiers(); - ptr_vector::const_iterator end = m_qm->end_quantifiers(); - for (; it != end; ++it) { - quantifier * q = *it; - if(!m_qm->mbqi_enabled(q)) continue; + for (quantifier * q : *m_qm) { + if (!(m_qm->mbqi_enabled(q) && + m_context->is_relevant(q) && + m_context->get_assignment(q) == l_true && + !m.is_lambda_def(q))) { + continue; + } + TRACE("model_checker", tout << "Check: " << mk_pp(q, m) << "\n"; tout << m_context->get_assignment(q) << "\n";); - if (m_context->is_relevant(q) && m_context->get_assignment(q) == l_true) { - if (m_params.m_mbqi_trace && q->get_qid() != symbol::null) { - verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n"; - } - found_relevant = true; - if (m.is_rec_fun_def(q)) { - if (!check_rec_fun(q, strict_rec_fun)) { - TRACE("model_checker", tout << "checking recursive function failed\n";); - num_failures++; - } - } - else if (!check(q)) { - if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) { - IF_VERBOSE(0, verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n"); - } - TRACE("model_checker", tout << "checking quantifier " << mk_pp(q, m) << " failed\n";); + if (m_params.m_mbqi_trace && q->get_qid() != symbol::null) { + verbose_stream() << "(smt.mbqi :checking " << q->get_qid() << ")\n"; + } + found_relevant = true; + if (m.is_rec_fun_def(q)) { + if (!check_rec_fun(q, strict_rec_fun)) { + TRACE("model_checker", tout << "checking recursive function failed\n";); num_failures++; } } + else if (!check(q)) { + if (m_params.m_mbqi_trace || get_verbosity_level() >= 5) { + IF_VERBOSE(0, verbose_stream() << "(smt.mbqi :failed " << q->get_qid() << ")\n"); + } + TRACE("model_checker", tout << "checking quantifier " << mk_pp(q, m) << " failed\n";); + num_failures++; + } } } @@ -466,7 +509,6 @@ namespace smt { void model_checker::reset_new_instances() { m_pinned_exprs.reset(); m_new_instances.reset(); - m_new_instances_region.reset(); } void model_checker::reset() { @@ -477,32 +519,30 @@ namespace smt { TRACE("model_checker_bug_detail", tout << "assert_new_instances, inconsistent: " << m_context->inconsistent() << "\n";); ptr_buffer bindings; ptr_vector dummy; - for (instance* inst : m_new_instances) { - quantifier * q = inst->m_q; + for (instance const& inst : m_new_instances) { + quantifier * q = inst.m_q; if (m_context->b_internalized(q)) { bindings.reset(); unsigned num_decls = q->get_num_decls(); - unsigned gen = inst->m_generation; + unsigned gen = inst.m_generation; + unsigned offset = inst.m_bindings_offset; for (unsigned i = 0; i < num_decls; i++) { - expr * b = inst->m_bindings[i]; + expr * b = m_pinned_exprs.get(offset + i); if (!m_context->e_internalized(b)) { - TRACE("model_checker_bug_detail", tout << "internalizing b:\n" << mk_pp(b, m) << "\n";); + TRACE("model_checker", tout << "internalizing b:\n" << mk_pp(b, m) << "\n";); m_context->internalize(b, false, gen); } bindings.push_back(m_context->get_enode(b)); } + + if (inst.m_def) { + m_context->internalize_assertion(inst.m_def, 0, gen); + } + TRACE("model_checker_bug_detail", tout << "instantiating... q:\n" << mk_pp(q, m) << "\n"; tout << "inconsistent: " << m_context->inconsistent() << "\n"; - tout << "bindings:\n"; - for (unsigned i = 0; i < num_decls; i++) { - expr * b = inst->m_bindings[i]; - tout << mk_pp(b, m) << "\n"; - }); - TRACE("model_checker_instance", - expr_ref inst_expr(m); - instantiate(m, q, inst->m_bindings, inst_expr); - tout << "(assert " << mk_ismt2_pp(inst_expr, m) << ")\n";); - m_context->add_instance(q, nullptr, num_decls, bindings.c_ptr(), gen, gen, gen, dummy); + tout << "bindings:\n" << expr_ref_vector(m, num_decls, m_pinned_exprs.c_ptr() + offset) << "\n";); + m_context->add_instance(q, nullptr, num_decls, bindings.c_ptr(), inst.m_def, gen, gen, gen, dummy); TRACE("model_checker_bug_detail", tout << "after instantiating, inconsistent: " << m_context->inconsistent() << "\n";); } } diff --git a/src/smt/smt_model_checker.h b/src/smt/smt_model_checker.h index dd63940b7..40a58efea 100644 --- a/src/smt/smt_model_checker.h +++ b/src/smt/smt_model_checker.h @@ -21,12 +21,12 @@ Revision History: #ifndef SMT_MODEL_CHECKER_H_ #define SMT_MODEL_CHECKER_H_ +#include "util/obj_hashtable.h" #include "ast/ast.h" #include "ast/array_decl_plugin.h" -#include "util/obj_hashtable.h" +#include "ast/normal_forms/defined_names.h" #include "smt/params/qi_params.h" #include "smt/params/smt_params.h" -#include "util/region.h" class proto_model; class model; @@ -56,7 +56,9 @@ namespace smt { friend class instantiation_set; void init_aux_context(); + void init_value2expr(); expr * get_term_from_ctx(expr * val); + expr_ref replace_value_from_ctx(expr * e); void restrict_to_universe(expr * sk, obj_hashtable const & universe); void assert_neg_q_m(quantifier * q, expr_ref_vector & sks); bool add_blocking_clause(model * cex, expr_ref_vector & sks); @@ -67,15 +69,12 @@ namespace smt { struct instance { quantifier * m_q; unsigned m_generation; - expr * m_bindings[0]; - static unsigned get_obj_size(unsigned num_bindings) { return sizeof(instance) + num_bindings * sizeof(expr*); } - instance(quantifier * q, expr * const * bindings, unsigned gen):m_q(q), m_generation(gen) { - memcpy(m_bindings, bindings, q->get_num_decls() * sizeof(expr*)); - } + expr * m_def; + unsigned m_bindings_offset; + instance(quantifier * q, unsigned offset, expr* def, unsigned gen):m_q(q), m_generation(gen), m_def(def), m_bindings_offset(offset) {} }; - region m_new_instances_region; - ptr_vector m_new_instances; + svector m_new_instances; expr_ref_vector m_pinned_exprs; bool add_instance(quantifier * q, model * cex, expr_ref_vector & sks, bool use_inv); void reset_new_instances(); @@ -86,7 +85,7 @@ namespace smt { struct is_model_value {}; expr_mark m_visited; bool contains_model_value(expr * e); - void add_instance(quantifier * q, expr_ref_vector const & bindings, unsigned max_generation); + void add_instance(quantifier * q, expr_ref_vector const & bindings, unsigned max_generation, expr * def); public: model_checker(ast_manager & m, qi_params const & p, model_finder & mf); diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 73f85faf6..b8b22b067 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -76,16 +76,16 @@ namespace smt { \brief Instantiation sets are the S_{k,j} sets in the Complete quantifier instantiation paper. */ class instantiation_set { - ast_manager & m_manager; + ast_manager & m; obj_map m_elems; // and the associated generation obj_map m_inv; expr_mark m_visited; public: - instantiation_set(ast_manager & m):m_manager(m) {} + instantiation_set(ast_manager & m):m(m) {} ~instantiation_set() { for (auto const& kv : m_elems) { - m_manager.dec_ref(kv.m_key); + m.dec_ref(kv.m_key); } m_elems.reset(); } @@ -95,10 +95,10 @@ namespace smt { void insert(expr * n, unsigned generation) { if (m_elems.contains(n) || contains_model_value(n)) return; - TRACE("model_finder", tout << mk_pp(n, m_manager) << "\n";); - m_manager.inc_ref(n); + TRACE("model_finder", tout << mk_pp(n, m) << "\n";); + m.inc_ref(n); m_elems.insert(n, generation); - SASSERT(!m_manager.is_model_value(n)); + SASSERT(!m.is_model_value(n)); } void remove(expr * n) { @@ -106,16 +106,16 @@ namespace smt { SASSERT(m_elems.contains(n)); SASSERT(m_inv.empty()); m_elems.erase(n); - m_manager.dec_ref(n); + m.dec_ref(n); } void display(std::ostream & out) const { for (auto const& kv : m_elems) { - out << mk_bounded_pp(kv.m_key, m_manager) << " [" << kv.m_value << "]\n"; + out << mk_bounded_pp(kv.m_key, m) << " [" << kv.m_value << "]\n"; } out << "inverse:\n"; for (auto const& kv : m_inv) { - out << mk_bounded_pp(kv.m_key, m_manager) << " -> " << mk_bounded_pp(kv.m_value, m_manager) << "\n"; + out << mk_bounded_pp(kv.m_key, m) << " -> " << mk_bounded_pp(kv.m_value, m) << "\n"; } } @@ -138,7 +138,7 @@ namespace smt { unsigned gen = kv.m_value; expr * t_val = ev.eval(t, true); if (!t_val) break; - TRACE("model_finder", tout << mk_pp(t, m_manager) << " " << mk_pp(t_val, m_manager) << "\n";); + TRACE("model_finder", tout << mk_pp(t, m) << " " << mk_pp(t_val, m) << "\n";); expr * old_t = nullptr; if (m_inv.find(t_val, old_t)) { @@ -161,13 +161,13 @@ namespace smt { struct is_model_value {}; void operator()(expr *n) { - if (m_manager.is_model_value(n)) { + if (m.is_model_value(n)) { throw is_model_value(); } } bool contains_model_value(expr* n) { - if (m_manager.is_model_value(n)) { + if (m.is_model_value(n)) { return true; } if (is_app(n) && to_app(n)->get_num_args() == 0) { @@ -393,6 +393,7 @@ namespace smt { ast_manager & m; arith_util m_arith; bv_util m_bv; + array_util m_array; ptr_vector m_nodes; unsigned m_next_node_id; key2node m_uvars; @@ -427,16 +428,16 @@ namespace smt { m_eval_cache_range.reset(); } - node * mk_node(key2node & m, ast * n, unsigned i, sort * s) { + node * mk_node(key2node & map, ast * n, unsigned i, sort * s) { node * r = nullptr; ast_idx_pair k(n, i); - if (m.find(k, r)) { + if (map.find(k, r)) { SASSERT(r->get_sort() == s); return r; } r = alloc(node, m_next_node_id, s); m_next_node_id++; - m.insert(k, r); + map.insert(k, r); m_nodes.push_back(r); return r; } @@ -468,6 +469,7 @@ namespace smt { m(m), m_arith(m), m_bv(m), + m_array(m), m_next_node_id(0), m_context(nullptr), m_ks(m), @@ -651,6 +653,7 @@ namespace smt { a set of values. */ app * get_k_for(sort * s) { + TRACE("model_finder", tout << sort_ref(s, m) << "\n";); SASSERT(is_infinite(s)); app * r = nullptr; if (m_sort2k.find(s, r)) @@ -709,6 +712,7 @@ namespace smt { } void set_projection_else(node * n) { + TRACE("model_finder", n->display(tout, m);); SASSERT(n->is_root()); SASSERT(!n->is_mono_proj()); instantiation_set const * s = n->get_instantiation_set(); @@ -856,7 +860,6 @@ namespace smt { bool is_signed = n->is_signed_proj(); unsigned sz = values.size(); SASSERT(sz > 0); - func_decl * p = m.mk_fresh_func_decl(1, &s, s); expr * pi = values[sz - 1]; expr_ref var(m); var = m.mk_var(0, s); @@ -872,11 +875,14 @@ namespace smt { } func_interp * rpi = alloc(func_interp, m, 1); rpi->set_else(pi); + func_decl * p = m.mk_fresh_func_decl(1, &s, s); + TRACE("model_finder", tout << expr_ref(pi, m) << "\n";); m_model->register_aux_decl(p, rpi); n->set_proj(p); } void mk_simple_proj(node * n) { + TRACE("model_finder", n->display(tout, m);); set_projection_else(n); ptr_buffer values; get_instantiation_set_values(n, values); @@ -887,7 +893,7 @@ namespace smt { if (n->get_else()) { expr * else_val = eval(n->get_else(), true); pi->set_else(else_val); - } + } for (expr * v : values) { pi->insert_new_entry(&v, v); } @@ -972,9 +978,8 @@ namespace smt { } } expr_ref_vector trail(m); - for (unsigned i = 0; i < need_fresh.size(); ++i) { + for (node * n : need_fresh) { expr * e; - node* n = need_fresh[i]; sort* s = n->get_sort(); if (!sort2elems.find(s, e)) { e = m.mk_fresh_const("elem", s); @@ -1173,10 +1178,7 @@ namespace smt { void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) override { node * A_f_i = s.get_A_f_i(m_f, m_arg_i); - enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); - enode_vector::const_iterator end = ctx->end_enodes_of(m_f); - for (; it != end; it++) { - enode * n = *it; + for (enode * n : ctx->enodes_of(m_f)) { if (ctx->is_relevant(n)) { // Remark: it is incorrect to use // n->get_arg(m_arg_i)->get_root() @@ -1203,10 +1205,7 @@ namespace smt { instantiation_set * s = uvar_inst_sets[m_var_j]; SASSERT(s != 0); - enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); - enode_vector::const_iterator end = ctx->end_enodes_of(m_f); - for (; it != end; it++) { - enode * n = *it; + for (enode * n : ctx->enodes_of(m_f)) { if (ctx->is_relevant(n)) { enode * e_arg = n->get_arg(m_arg_i); expr * arg = e_arg->get_owner(); @@ -1255,10 +1254,7 @@ namespace smt { // there is no finite fixpoint... we just copy the i-th arguments of A_f_i - m_offset // hope for the best... node * S_j = s.get_uvar(q, m_var_j); - enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); - enode_vector::const_iterator end = ctx->end_enodes_of(m_f); - for (; it != end; it++) { - enode * n = *it; + for (enode * n : ctx->enodes_of(m_f)) { if (ctx->is_relevant(n)) { arith_rewriter arith_rw(ctx->get_manager()); bv_util bv(ctx->get_manager()); @@ -1375,7 +1371,7 @@ namespace smt { class select_var : public qinfo { protected: - ast_manager & m_manager; + ast_manager & m; array_util m_array; app * m_select; // It must satisfy is_auf_select... see bool is_auf_select(expr * t) const unsigned m_arg_i; @@ -1384,6 +1380,7 @@ namespace smt { app * get_array() const { return to_app(m_select->get_arg(0)); } func_decl * get_array_func_decl(app * ground_array, auf_solver & s) { + TRACE("model_evaluator", tout << expr_ref(ground_array, m) << "\n";); expr * ground_array_interp = s.eval(ground_array, false); if (ground_array_interp != nullptr && m_array.is_as_array(ground_array_interp)) return m_array.get_as_array_func_decl(ground_array_interp); @@ -1391,7 +1388,7 @@ namespace smt { } public: - select_var(ast_manager & m, app * s, unsigned i, unsigned j):m_manager(m), m_array(m), m_select(s), m_arg_i(i), m_var_j(j) {} + select_var(ast_manager & m, app * s, unsigned i, unsigned j):m(m), m_array(m), m_select(s), m_arg_i(i), m_var_j(j) {} ~select_var() override {} char const * get_kind() const override { @@ -1406,7 +1403,7 @@ namespace smt { } void display(std::ostream & out) const override { - out << "(" << mk_bounded_pp(m_select, m_manager) << ":" << m_arg_i << " -> v!" << m_var_j << ")"; + out << "(" << mk_bounded_pp(m_select, m) << ":" << m_arg_i << " -> v!" << m_var_j << ")"; } void process_auf(quantifier * q, auf_solver & s, context * ctx) override { @@ -1415,7 +1412,7 @@ namespace smt { TRACE("select_var", tout << "enodes matching: "; display(tout); tout << "\n"; for (enode* n : arrays) { - tout << "#" << n->get_owner()->get_id() << "\n" << mk_pp(n->get_owner(), m_manager) << "\n"; + tout << "#" << n->get_owner()->get_id() << "\n" << mk_pp(n->get_owner(), m) << "\n"; }); node * n1 = s.get_uvar(q, m_var_j); for (enode* n : arrays) { @@ -1574,10 +1571,7 @@ namespace smt { // For uninterpreted sorts, we add all terms in the context. // See Section 4.1 in the paper "Complete Quantifier Instantiation" node * S_q_i = slv.get_uvar(q, m_var_i); - ptr_vector::const_iterator it = ctx->begin_enodes(); - ptr_vector::const_iterator end = ctx->end_enodes(); - for (; it != end; ++it) { - enode * n = *it; + for (enode * n : ctx->enodes()) { if (ctx->is_relevant(n) && get_sort(n->get_owner()) == s) { S_q_i->insert(n->get_owner(), n->get_generation()); } @@ -1623,7 +1617,7 @@ namespace smt { class cond_macro { protected: - ast_manager & m_manager; + ast_manager & m; func_decl * m_f; expr * m_def; expr * m_cond; @@ -1633,7 +1627,7 @@ namespace smt { unsigned m_weight; public: cond_macro(ast_manager & m, func_decl * f, expr * def, expr * cond, bool ineq, bool satisfy_atom, bool hint, unsigned weight): - m_manager(m), + m(m), m_f(f), m_def(def), m_cond(cond), @@ -1641,14 +1635,14 @@ namespace smt { m_satisfy_atom(satisfy_atom), m_hint(hint), m_weight(weight) { - m_manager.inc_ref(m_def); - m_manager.inc_ref(m_cond); + m.inc_ref(m_def); + m.inc_ref(m_cond); SASSERT(!m_hint || m_cond == 0); } ~cond_macro() { - m_manager.dec_ref(m_def); - m_manager.dec_ref(m_cond); + m.dec_ref(m_def); + m.dec_ref(m_cond); } func_decl * get_f() const { return m_f; } @@ -1657,7 +1651,7 @@ namespace smt { expr * get_cond() const { return m_cond; } - bool is_unconditional() const { return m_cond == nullptr || m_manager.is_true(m_cond); } + bool is_unconditional() const { return m_cond == nullptr || m.is_true(m_cond); } bool satisfy_atom() const { return m_satisfy_atom; } @@ -1668,11 +1662,11 @@ namespace smt { } void display(std::ostream & out) const { - out << "[" << m_f->get_name() << " -> " << mk_bounded_pp(m_def, m_manager, 6); + out << "[" << m_f->get_name() << " -> " << mk_bounded_pp(m_def, m, 6); if (m_hint) out << " *hint*"; else - out << " when " << mk_bounded_pp(m_cond, m_manager, 6); + out << " when " << mk_bounded_pp(m_cond, m, 6); out << "] weight: " << m_weight; } @@ -1739,7 +1733,7 @@ namespace smt { m_has_x_eq_y(false), m_the_one(nullptr), m_uvar_inst_sets(nullptr) { - if (has_quantifiers(q->get_expr())) { + if (has_quantifiers(q->get_expr()) && !m.is_lambda_def(q)) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { // [Leo]: This warning message is not useful. @@ -1758,7 +1752,7 @@ namespace smt { } CTRACE("model_finder_bug", has_quantifiers(m_flat_q->get_expr()), tout << mk_pp(q, m) << "\n" << mk_pp(m_flat_q, m) << "\n";); - SASSERT(!has_quantifiers(m_flat_q->get_expr())); + SASSERT(m.is_lambda_def(q) || !has_quantifiers(m_flat_q->get_expr())); } ~quantifier_info() { @@ -1787,7 +1781,6 @@ namespace smt { ptr_vector const& macros() const { return m_cond_macros; } - void set_the_one(func_decl * m) { m_the_one = m; } @@ -1880,7 +1873,7 @@ namespace smt { */ class quantifier_analyzer { model_finder& m_mf; - ast_manager & m_manager; + ast_manager & m; macro_util m_mutil; array_util m_array_util; arith_util m_arith_util; @@ -1909,7 +1902,7 @@ namespace smt { bool is_var_plus_ground(expr * n, var * & v, expr_ref & t) { bool inv; - TRACE("is_var_plus_ground", tout << mk_pp(n, m_manager) << "\n"; + TRACE("is_var_plus_ground", tout << mk_pp(n, m) << "\n"; tout << "is_var_plus_ground: " << is_var_plus_ground(n, inv, v, t) << "\n"; tout << "inv: " << inv << "\n";); return is_var_plus_ground(n, inv, v, t) && !inv; @@ -1953,7 +1946,7 @@ namespace smt { bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) { inv = false; // true if invert the sign - TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";); + TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m) << " " << mk_ismt2_pp(rhs, m) << "\n";); if (is_var(lhs) && is_ground(rhs)) { v = to_var(lhs); t = rhs; @@ -1967,7 +1960,7 @@ namespace smt { return true; } else { - expr_ref tmp(m_manager); + expr_ref tmp(m); if (is_var_plus_ground(lhs, inv, v, tmp) && is_ground(rhs)) { if (inv) mk_sub(tmp, rhs, t); @@ -1994,7 +1987,7 @@ namespace smt { bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) { if (!is_app(n)) return false; - if (m_manager.is_eq(n)) + if (m.is_eq(n)) return is_var_and_ground(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v, t); return false; } @@ -2030,7 +2023,7 @@ namespace smt { } bool is_x_eq_y_atom(expr * n, var * & v1, var * & v2) { - return m_manager.is_eq(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); + return m.is_eq(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); } bool is_x_gle_y_atom(expr * n, var * & v1, var * & v2) { @@ -2042,28 +2035,28 @@ namespace smt { return false; if (sign) { bool r = is_le_ge(atom) && is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, t); - CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m) << "\n--->\n" + << mk_ismt2_pp(v, m) << " " << mk_ismt2_pp(t, m) << "\n"; tout << "sign: " << sign << "\n";); return r; } else { if (is_le_ge(atom)) { - expr_ref tmp(m_manager); + expr_ref tmp(m); bool le = is_le(atom); bool inv = false; if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp, inv)) { if (inv) le = !le; - sort * s = m_manager.get_sort(tmp); - expr_ref one(m_manager); + sort * s = m.get_sort(tmp); + expr_ref one(m); one = mk_one(s); if (le) mk_add(tmp, one, t); else mk_sub(tmp, one, t); - TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m) << "\n--->\n" + << mk_ismt2_pp(v, m) << " " << mk_ismt2_pp(t, m) << "\n"; tout << "sign: " << sign << "\n";); return true; } @@ -2113,9 +2106,9 @@ namespace smt { } var * v; - expr_ref k(m_manager); + expr_ref k(m); if (is_var_plus_ground(arg, v, k)) { - insert_qinfo(alloc(f_var_plus_offset, m_manager, t->get_decl(), i, v->get_idx(), k.get())); + insert_qinfo(alloc(f_var_plus_offset, m, t->get_decl(), i, v->get_idx(), k.get())); continue; } @@ -2157,7 +2150,7 @@ namespace smt { for (unsigned i = 1; i < num_args; i++) { expr * arg = t->get_arg(i); if (is_var(arg)) { - insert_qinfo(alloc(select_var, m_manager, t, i, to_var(arg)->get_idx())); + insert_qinfo(alloc(select_var, m, t, i, to_var(arg)->get_idx())); } else { SASSERT(is_ground(arg)); @@ -2174,7 +2167,7 @@ namespace smt { void process_app(app * t) { SASSERT(!is_ground(t)); - if (t->get_family_id() != m_manager.get_basic_family_id()) { + if (t->get_family_id() != m.get_basic_family_id()) { m_info->m_ng_decls.insert(t->get_decl()); } @@ -2191,7 +2184,7 @@ namespace smt { expr * curr = m_ttodo.back(); m_ttodo.pop_back(); - if (m_manager.is_bool(curr)) { + if (m.is_bool(curr)) { // formula nested in a term. visit_formula(curr, POS); visit_formula(curr, NEG); @@ -2212,30 +2205,30 @@ namespace smt { } void process_literal(expr * atom, bool sign) { - CTRACE("model_finder_bug", is_ground(atom), tout << mk_pp(atom, m_manager) << "\n";); + CTRACE("model_finder_bug", is_ground(atom), tout << mk_pp(atom, m) << "\n";); SASSERT(!is_ground(atom)); - SASSERT(m_manager.is_bool(atom)); + SASSERT(m.is_bool(atom)); if (is_var(atom)) { if (sign) { // atom (not X) can be viewed as X != true - insert_qinfo(alloc(x_neq_t, m_manager, to_var(atom)->get_idx(), m_manager.mk_true())); + insert_qinfo(alloc(x_neq_t, m, to_var(atom)->get_idx(), m.mk_true())); } else { // atom X can be viewed as X != false - insert_qinfo(alloc(x_neq_t, m_manager, to_var(atom)->get_idx(), m_manager.mk_false())); + insert_qinfo(alloc(x_neq_t, m, to_var(atom)->get_idx(), m.mk_false())); } return; } if (is_app(atom)) { var * v, * v1, * v2; - expr_ref t(m_manager); + expr_ref t(m); if (is_x_eq_t_atom(atom, v, t)) { if (sign) - insert_qinfo(alloc(x_neq_t, m_manager, v->get_idx(), t)); + insert_qinfo(alloc(x_neq_t, m, v->get_idx(), t)); else - insert_qinfo(alloc(x_eq_t, m_manager, v->get_idx(), t)); + insert_qinfo(alloc(x_eq_t, m, v->get_idx(), t)); } else if (is_x_eq_y_atom(atom, v1, v2)) { if (sign) @@ -2252,7 +2245,7 @@ namespace smt { insert_qinfo(alloc(x_leq_y, v1->get_idx(), v2->get_idx())); } else if (is_x_gle_t_atom(atom, sign, v, t)) { - insert_qinfo(alloc(x_gle_t, m_manager, v->get_idx(), t)); + insert_qinfo(alloc(x_gle_t, m, v->get_idx(), t)); } else { process_app(to_app(atom)); @@ -2299,7 +2292,7 @@ namespace smt { polarity pol = e.second; m_ftodo.pop_back(); if (is_app(curr)) { - if (to_app(curr)->get_family_id() == m_manager.get_basic_family_id() && m_manager.is_bool(curr)) { + if (to_app(curr)->get_family_id() == m.get_basic_family_id() && m.is_bool(curr)) { switch (static_cast(to_app(curr)->get_decl_kind())) { case OP_IMPLIES: case OP_XOR: @@ -2316,7 +2309,7 @@ namespace smt { process_ite(to_app(curr), pol); break; case OP_EQ: - if (m_manager.is_bool(to_app(curr)->get_arg(0))) { + if (m.is_bool(to_app(curr)->get_arg(0))) { process_iff(to_app(curr)); } else { @@ -2333,7 +2326,7 @@ namespace smt { } } else if (is_var(curr)) { - SASSERT(m_manager.is_bool(curr)); + SASSERT(m.is_bool(curr)); process_literal(curr, pol); } else { @@ -2344,32 +2337,32 @@ namespace smt { } void process_formula(expr * n) { - SASSERT(m_manager.is_bool(n)); + SASSERT(m.is_bool(n)); visit_formula(n, POS); } void process_clause(expr * cls) { - SASSERT(is_clause(m_manager, cls)); - unsigned num_lits = get_clause_num_literals(m_manager, cls); + SASSERT(is_clause(m, cls)); + unsigned num_lits = get_clause_num_literals(m, cls); for (unsigned i = 0; i < num_lits; i++) { - expr * lit = get_clause_literal(m_manager, cls, i); - SASSERT(is_literal(m_manager, lit)); + expr * lit = get_clause_literal(m, cls, i); + SASSERT(is_literal(m, lit)); expr * atom; bool sign; - get_literal_atom_sign(m_manager, lit, atom, sign); + get_literal_atom_sign(m, lit, atom, sign); if (!is_ground(atom)) process_literal(atom, sign); } } void collect_macro_candidates(quantifier * q) { - macro_util::macro_candidates candidates(m_manager); + macro_util::macro_candidates candidates(m); m_mutil.collect_macro_candidates(q, candidates); unsigned num_candidates = candidates.size(); for (unsigned i = 0; i < num_candidates; i++) { - cond_macro * m = alloc(cond_macro, m_manager, candidates.get_f(i), candidates.get_def(i), candidates.get_cond(i), + cond_macro * mc = alloc(cond_macro, m, candidates.get_f(i), candidates.get_def(i), candidates.get_cond(i), candidates.ineq(i), candidates.satisfy_atom(i), candidates.hint(i), q->get_weight()); - m_info->insert_macro(m); + m_info->insert_macro(mc); } } @@ -2377,7 +2370,7 @@ namespace smt { public: quantifier_analyzer(model_finder& mf, ast_manager & m): m_mf(mf), - m_manager(m), + m(m), m_mutil(m), m_array_util(m), m_arith_util(m), @@ -2389,13 +2382,14 @@ namespace smt { void operator()(quantifier_info * d) { m_info = d; quantifier * q = d->get_flat_q(); + if (m.is_lambda_def(q)) return; expr * e = q->get_expr(); SASSERT(!has_quantifiers(e)); reset_cache(); SASSERT(m_ttodo.empty()); SASSERT(m_ftodo.empty()); - if (is_clause(m_manager, e)) { + if (is_clause(m, e)) { process_clause(e); } else { @@ -2419,7 +2413,7 @@ namespace smt { */ class base_macro_solver { protected: - ast_manager & m_manager; + ast_manager & m; obj_map const & m_q2info; proto_model * m_model; @@ -2434,18 +2428,18 @@ namespace smt { SASSERT(f_else != 0); func_interp * fi = m_model->get_func_interp(f); if (fi == nullptr) { - fi = alloc(func_interp, m_manager, f->get_arity()); + fi = alloc(func_interp, m, f->get_arity()); m_model->register_decl(f, fi); } fi->set_else(f_else); - TRACE("model_finder", tout << f->get_name() << " " << mk_pp(f_else, m_manager) << "\n";); + TRACE("model_finder", tout << f->get_name() << " " << mk_pp(f_else, m) << "\n";); } virtual bool process(ptr_vector const & qs, ptr_vector & new_qs, ptr_vector & residue) = 0; public: base_macro_solver(ast_manager & m, obj_map const & q2i): - m_manager(m), + m(m), m_q2info(q2i), m_model(nullptr) { } @@ -2647,7 +2641,7 @@ namespace smt { bool is_candidate(quantifier * q) const { quantifier_info * qi = get_qinfo(q); - for (cond_macro * m : qi->macros()) { + for (cond_macro* m : qi->macros()) { if (m->satisfy_atom() && !m_forbidden.contains(m->get_f())) return true; } @@ -2708,7 +2702,7 @@ namespace smt { void display_qcandidates(std::ostream & out, ptr_vector const & qcandidates) const { for (quantifier * q : qcandidates) { - out << q->get_qid() << " ->\n" << mk_pp(q, m_manager) << "\n"; + out << q->get_qid() << " ->\n" << mk_pp(q, m) << "\n"; quantifier_info * qi = get_qinfo(q); qi->display(out); out << "------\n"; @@ -2724,7 +2718,7 @@ namespace smt { func_decl * f = kv.get_key1(); expr * def = kv.get_key2(); quantifier_set * s = kv.get_value(); - out << f->get_name() << " " << mk_pp(def, m_manager) << " ->\n"; display_quantifier_set(out, s); + out << f->get_name() << " " << mk_pp(def, m) << " ->\n"; display_quantifier_set(out, s); } } @@ -2846,7 +2840,7 @@ namespace smt { m_satisfied.push_scope(); m_residue.push_scope(); - TRACE("model_finder", tout << f->get_name() << " " << mk_pp(def, m_manager) << "\n";); + TRACE("model_finder", tout << f->get_name() << " " << mk_pp(def, m) << "\n";); m_fs.insert(f, def); if (update_satisfied_residue(f, def)) { @@ -3023,7 +3017,7 @@ namespace smt { qi_params const * m_qi_params; bool add_macro(func_decl * f, expr * f_else) { - TRACE("model_finder", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m_manager) << "\n";); + TRACE("model_finder", tout << "trying to add macro for " << f->get_name() << "\n" << mk_pp(f_else, m) << "\n";); func_decl_set * s = m_dependencies.mk_func_decl_set(); m_dependencies.collect_ng_func_decls(f_else, s); if (!m_dependencies.insert(f, s)) { @@ -3092,23 +3086,23 @@ namespace smt { } void process(func_decl * f, ptr_vector const & qs, obj_hashtable & removed) { - expr_ref fi_else(m_manager); + expr_ref fi_else(m); ptr_buffer to_remove; for (quantifier * q : qs) { if (removed.contains(q)) continue; - cond_macro * m = get_macro_for(f, q); - if (!m) + cond_macro * cm = get_macro_for(f, q); + if (!cm) continue; - SASSERT(!m->is_hint()); - if (m->is_unconditional()) + SASSERT(!cm->is_hint()); + if (cm->is_unconditional()) return; // f is part of a full macro... ignoring it. to_remove.push_back(q); if (fi_else.get() == nullptr) { - fi_else = m->get_def(); + fi_else = cm->get_def(); } else { - fi_else = m_manager.mk_ite(m->get_cond(), m->get_def(), fi_else); + fi_else = m.mk_ite(cm->get_cond(), cm->get_def(), fi_else); } } if (fi_else.get() != nullptr && add_macro(f, fi_else)) { @@ -3166,7 +3160,7 @@ namespace smt { // ----------------------------------- model_finder::model_finder(ast_manager & m): - m_manager(m), + m(m), m_context(nullptr), m_analyzer(alloc(quantifier_analyzer, *this, m)), m_auf_solver(alloc(auf_solver, m)), @@ -3206,8 +3200,8 @@ namespace smt { } void model_finder::register_quantifier(quantifier * q) { - TRACE("model_finder", tout << "registering:\n" << mk_pp(q, m_manager) << "\n";); - quantifier_info * new_info = alloc(quantifier_info, *this, m_manager, q); + TRACE("model_finder", tout << "registering:\n" << mk_pp(q, m) << "\n";); + quantifier_info * new_info = alloc(quantifier_info, *this, m, q); m_q2info.insert(q, new_info); m_quantifiers.push_back(q); m_analyzer->operator()(new_info); @@ -3261,9 +3255,9 @@ namespace smt { } } - void model_finder::process_auf(ptr_vector const & qs, proto_model * m) { + void model_finder::process_auf(ptr_vector const & qs, proto_model * mdl) { m_auf_solver->reset(); - m_auf_solver->set_model(m); + m_auf_solver->set_model(mdl); for (quantifier * q : qs) { quantifier_info * qi = get_quantifier_info(q); @@ -3280,7 +3274,7 @@ namespace smt { for (quantifier * q : qs) { quantifier_info * qi = get_quantifier_info(q); quantifier * fq = qi->get_flat_q(); - tout << "#" << fq->get_id() << " ->\n" << mk_pp(fq, m_manager) << "\n"; + tout << "#" << fq->get_id() << " ->\n" << mk_pp(fq, m) << "\n"; } m_auf_solver->display_nodes(tout);); } @@ -3310,11 +3304,8 @@ namespace smt { \brief Clean leftovers from previous invocations to fix_model. */ void model_finder::cleanup_quantifier_infos(ptr_vector const & qs) { - ptr_vector::const_iterator it = qs.begin(); - ptr_vector::const_iterator end = qs.end(); - for (; it != end; ++it) { - quantifier_info * qi = get_quantifier_info(*it); - qi->reset_the_one(); + for (quantifier* q : qs) { + get_quantifier_info(q)->reset_the_one(); } } @@ -3356,7 +3347,7 @@ namespace smt { quantifier * flat_q = get_flat_quantifier(q); SASSERT(flat_q->get_num_decls() >= q->get_num_decls()); instantiation_set const * r = m_auf_solver->get_uvar_inst_set(flat_q, flat_q->get_num_decls() - q->get_num_decls() + i); - TRACE("model_finder", tout << "q: #" << q->get_id() << "\n" << mk_pp(q,m_manager) << "\nflat_q: " << mk_pp(flat_q, m_manager) + TRACE("model_finder", tout << "q: #" << q->get_id() << "\n" << mk_pp(q,m) << "\nflat_q: " << mk_pp(flat_q, m) << "\ni: " << i << " " << flat_q->get_num_decls() - q->get_num_decls() + i << "\n";); if (r != nullptr) return r; @@ -3365,7 +3356,6 @@ namespace smt { quantifier_info * qinfo = get_quantifier_info(q); SASSERT(qinfo); SASSERT(qinfo->get_the_one() != 0); - return qinfo->get_macro_based_inst_set(i, m_context, *(m_auf_solver.get())); } @@ -3415,15 +3405,13 @@ namespace smt { if (inv.empty()) continue; // nothing to do ptr_buffer eqs; - obj_map::iterator it = inv.begin(); - obj_map::iterator end = inv.end(); - for (; it != end; ++it) { - expr * val = (*it).m_key; - eqs.push_back(m_manager.mk_eq(sk, val)); + for (auto const& kv : inv) { + expr * val = kv.m_key; + eqs.push_back(m.mk_eq(sk, val)); } - expr_ref new_cnstr(m_manager); - new_cnstr = m_manager.mk_or(eqs.size(), eqs.c_ptr()); - TRACE("model_finder", tout << "assert_restriction:\n" << mk_pp(new_cnstr, m_manager) << "\n";); + expr_ref new_cnstr(m); + new_cnstr = m.mk_or(eqs.size(), eqs.c_ptr()); + TRACE("model_finder", tout << "assert_restriction:\n" << mk_pp(new_cnstr, m) << "\n";); aux_ctx->assert_expr(new_cnstr); asserted_something = true; } @@ -3435,7 +3423,7 @@ namespace smt { if (sz > 0) { for (unsigned i = 0; i < sz; i++) { expr * c = m_new_constraints.get(i); - TRACE("model_finder_bug_detail", tout << "asserting new constraint: " << mk_pp(c, m_manager) << "\n";); + TRACE("model_finder_bug_detail", tout << "asserting new constraint: " << mk_pp(c, m) << "\n";); m_context->internalize(c, true); literal l(m_context->get_literal(c)); m_context->mark_as_relevant(l); diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index 2b79ab265..842a18db8 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -74,7 +74,7 @@ namespace smt { typedef mf::non_auf_macro_solver non_auf_macro_solver; typedef mf::instantiation_set instantiation_set; - ast_manager & m_manager; + ast_manager & m; context * m_context; scoped_ptr m_analyzer; scoped_ptr m_auf_solver; diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 9ba2c6165..5417785d6 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -24,6 +24,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/smt_model_generator.h" #include "smt/proto_model/proto_model.h" +#include "model/model_v2_pp.h" namespace smt { @@ -51,11 +52,9 @@ namespace smt { SASSERT(!m_model); // PARAM-TODO smt_params ---> params_ref m_model = alloc(proto_model, m_manager); // , m_context->get_fparams()); - ptr_vector::const_iterator it = m_context->begin_theories(); - ptr_vector::const_iterator end = m_context->end_theories(); - for (; it != end; ++it) { - TRACE("model", tout << "init_model for theory: " << (*it)->get_name() << "\n";); - (*it)->init_model(*this); + for (theory* th : m_context->theories()) { + TRACE("model_generator_bug", tout << "init_model for theory: " << th->get_name() << "\n";); + th->init_model(*this); } } @@ -82,10 +81,7 @@ namespace smt { */ void model_generator::mk_value_procs(obj_map & root2proc, ptr_vector & roots, ptr_vector & procs) { - ptr_vector::const_iterator it = m_context->begin_enodes(); - ptr_vector::const_iterator end = m_context->end_enodes(); - for (; it != end; ++it) { - enode * r = *it; + for (enode * r : m_context->enodes()) { if (r == r->get_root() && m_context->is_relevant(r)) { roots.push_back(r); sort * s = m_manager.get_sort(r->get_owner()); @@ -201,10 +197,7 @@ namespace smt { SASSERT(proc); buffer dependencies; proc->get_dependencies(dependencies); - buffer::const_iterator it = dependencies.begin(); - buffer::const_iterator end = dependencies.end(); - for (; it != end; ++it) { - model_value_dependency const & dep = *it; + for (model_value_dependency const& dep : dependencies) { visit_child(dep, colors, todo, visited); TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> "; if (dep.is_fresh_value()) tout << "fresh!" << dep.get_value()->get_idx(); @@ -308,10 +301,7 @@ namespace smt { mk_value_procs(root2proc, roots, procs); top_sort_sources(roots, root2proc, sources); TRACE("sorted_sources", - svector::const_iterator it = sources.begin(); - svector::const_iterator end = sources.end(); - for (; it != end; ++it) { - source const & curr = *it; + for (source const& curr : sources) { if (curr.is_fresh_value()) { tout << "fresh!" << curr.get_value()->get_idx() << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; } @@ -326,11 +316,7 @@ namespace smt { tout << " is_fresh: " << proc->is_fresh() << "\n"; } }); - svector::const_iterator it = sources.begin(); - svector::const_iterator end = sources.end(); - for (; it != end; ++it) { - source const & curr = *it; - + for (source const& curr : sources) { if (curr.is_fresh_value()) { sort * s = curr.get_value()->get_sort(); TRACE("model_fresh_bug", tout << "mk fresh!" << curr.get_value()->get_idx() << " : " << mk_pp(s, m_manager) << "\n";); @@ -349,10 +335,7 @@ namespace smt { VERIFY(root2proc.find(n, proc)); SASSERT(proc); proc->get_dependencies(dependencies); - buffer::const_iterator it2 = dependencies.begin(); - buffer::const_iterator end2 = dependencies.end(); - for (; it2 != end2; ++it2) { - model_value_dependency const & d = *it2; + for (model_value_dependency const& d : dependencies) { if (d.is_fresh_value()) { CTRACE("mg_top_sort", !d.get_value()->get_value(), tout << "#" << n->get_owner_id() << " -> "; @@ -381,10 +364,7 @@ namespace smt { m_extra_fresh_values.reset(); // send model - ptr_vector::const_iterator it3 = m_context->begin_enodes(); - ptr_vector::const_iterator end3 = m_context->end_enodes(); - for (; it3 != end3; ++it3) { - enode * n = *it3; + for (enode * n : m_context->enodes()) { if (is_uninterp_const(n->get_owner()) && m_context->is_relevant(n)) { func_decl * d = n->get_owner()->get_decl(); TRACE("mg_top_sort", tout << d->get_name() << " " << (m_hidden_ufs.contains(d)?"hidden":"visible") << "\n";); @@ -484,17 +464,12 @@ namespace smt { } void model_generator::finalize_theory_models() { - ptr_vector::const_iterator it = m_context->begin_theories(); - ptr_vector::const_iterator end = m_context->end_theories(); - for (; it != end; ++it) - (*it)->finalize_model(*this); + for (theory* th : m_context->theories()) + th->finalize_model(*this); } void model_generator::register_existing_model_values() { - ptr_vector::const_iterator it = m_context->begin_enodes(); - ptr_vector::const_iterator end = m_context->end_enodes(); - for (; it != end; ++it) { - enode * r = *it; + for (enode * r : m_context->enodes()) { if (r == r->get_root() && m_context->is_relevant(r)) { expr * n = r->get_owner(); if (m_manager.is_model_value(n)) { @@ -531,6 +506,7 @@ namespace smt { mk_func_interps(); finalize_theory_models(); register_macros(); + TRACE("model", model_v2_pp(tout, *m_model, true);); return m_model; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 1f6811a0f..48c59003c 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -107,6 +107,7 @@ namespace smt { bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, + expr* def, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, @@ -116,7 +117,7 @@ namespace smt { return false; } get_stat(q)->update_max_generation(max_generation); - fingerprint * f = m_context.add_fingerprint(q, q->get_id(), num_bindings, bindings); + fingerprint * f = m_context.add_fingerprint(q, q->get_id(), num_bindings, bindings, def); if (f) { if (has_trace_stream()) { std::ostream & out = trace_stream(); @@ -291,16 +292,17 @@ namespace smt { bool quantifier_manager::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, + expr* def, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes) { - return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes); + return m_imp->add_instance(q, pat, num_bindings, bindings, def, max_generation, min_top_generation, max_generation, used_enodes); } - bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) { + bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, expr* def, unsigned generation) { ptr_vector tmp; - return add_instance(q, nullptr, num_bindings, bindings, generation, generation, generation, tmp); + return add_instance(q, nullptr, num_bindings, bindings, def, generation, generation, generation, tmp); } void quantifier_manager::init_search_eh() { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index ad5f58e49..dde7ec2c4 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -54,11 +54,12 @@ namespace smt { bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, + expr* def, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); - bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0); + bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, expr* def, unsigned generation = 0); void init_search_eh(); void assign_eh(quantifier * q); @@ -91,6 +92,8 @@ namespace smt { ptr_vector::const_iterator begin_quantifiers() const; ptr_vector::const_iterator end_quantifiers() const; + ptr_vector::const_iterator begin() const { return begin_quantifiers(); } + ptr_vector::const_iterator end() const { return end_quantifiers(); } unsigned num_quantifiers() const; }; diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 72a720d98..85c0ca183 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -51,10 +51,7 @@ namespace smt { bool quick_checker::collector::check_arg(enode * n, func_decl * f, unsigned i) { if (!f || !m_conservative) return true; - enode_vector::const_iterator it = m_context.begin_enodes_of(f); - enode_vector::const_iterator end = m_context.end_enodes_of(f); - for (; it != end; ++it) { - enode * curr = *it; + for (enode * curr : m_context.enodes_of(f)) { if (m_context.is_relevant(curr) && curr->is_cgr() && i < curr->get_num_args() && curr->get_arg(i)->get_root() == n->get_root()) return true; } @@ -76,10 +73,7 @@ namespace smt { if (s.empty()) continue; ns.reset(); - enode_vector::const_iterator it = m_context.begin_enodes_of(f); - enode_vector::const_iterator end = m_context.end_enodes_of(f); - for (; it != end; ++it) { - enode * curr = *it; + for (enode * curr : m_context.enodes_of(f)) { if (m_context.is_relevant(curr) && curr->is_cgr() && check_arg(curr, p, i) && j < curr->get_num_args()) { enode * arg = curr->get_arg(j)->get_root(); // intersection @@ -93,10 +87,7 @@ namespace smt { else { m_already_found[idx] = true; enode_set & s = m_candidates[idx]; - enode_vector::const_iterator it = m_context.begin_enodes_of(f); - enode_vector::const_iterator end = m_context.end_enodes_of(f); - for (; it != end; ++it) { - enode * curr = *it; + for (enode * curr : m_context.enodes_of(f)) { if (m_context.is_relevant(curr) && curr->is_cgr() && check_arg(curr, p, i) && j < curr->get_num_args()) { enode * arg = curr->get_arg(j)->get_root(); s.insert(arg); @@ -133,10 +124,7 @@ namespace smt { enode_vector & v = candidates[i]; v.reset(); enode_set & s = m_candidates[i]; - enode_set::iterator it = s.begin(); - enode_set::iterator end = s.end(); - for (; it != end; ++it) { - enode * curr = *it; + for (enode * curr : s) { v.push_back(curr); } } @@ -145,10 +133,8 @@ namespace smt { for (unsigned i = 0; i < m_num_vars; i++) { tout << "var " << i << ":"; enode_vector & v = candidates[i]; - enode_vector::iterator it = v.begin(); - enode_vector::iterator end = v.end(); - for (; it != end; ++it) - tout << " #" << (*it)->get_owner_id(); + for (enode * n : v) + tout << " #" << n->get_owner_id(); tout << "\n"; }); } @@ -226,10 +212,8 @@ namespace smt { tout << "candidates:\n"; for (unsigned i = 0; i < m_num_bindings; i++) { enode_vector & v = m_candidate_vectors[i]; - enode_vector::iterator it = v.begin(); - enode_vector::iterator end = v.end(); - for (; it != end; ++it) - tout << "#" << (*it)->get_owner_id() << " "; + for (enode * n : v) + tout << "#" << n->get_owner_id() << " "; tout << "\n"; }); bool result = false; @@ -251,7 +235,8 @@ namespace smt { TRACE("quick_checker_sizes", tout << "found new candidate\n"; for (unsigned i = 0; i < m_num_bindings; i++) tout << "#" << m_bindings[i]->get_owner_id() << " "; tout << "\n";); unsigned max_generation = get_max_generation(m_num_bindings, m_bindings.c_ptr()); - if (m_context.add_instance(q, nullptr /* no pattern was used */, m_num_bindings, m_bindings.c_ptr(), max_generation, + if (m_context.add_instance(q, nullptr /* no pattern was used */, m_num_bindings, m_bindings.c_ptr(), nullptr, + max_generation, 0, // min_top_generation is only available for instances created by the MAM 0, // max_top_generation is only available for instances created by the MAM empty_used_enodes)) diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index b8f76f9ad..ffeb1b274 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -383,7 +383,7 @@ namespace smt { } } TRACE("array", tout << "m_found_unsupported_op: " << m_found_unsupported_op << " " << r << "\n";); - if (r == FC_DONE && m_found_unsupported_op) + if (r == FC_DONE && m_found_unsupported_op && !get_context().get_fparams().m_array_fake_support) r = FC_GIVEUP; return r; } diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index a0e9fad2b..c024c0da0 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -33,8 +33,12 @@ namespace smt { } void theory_array_base::found_unsupported_op(expr * n) { - TRACE("array", tout << mk_ll_pp(n, get_manager()) << "\n";); - if (!m_found_unsupported_op) { + if (!get_context().get_fparams().m_array_fake_support && !m_found_unsupported_op) { + //array_util autil(get_manager()); + //func_decl* f = 0; + //if (autil.is_as_array(n, f) && f->is_skolem()) return; + TRACE("array", tout << mk_ll_pp(n, get_manager()) << "\n";); + get_context().push_trail(value_trail(m_found_unsupported_op)); m_found_unsupported_op = true; } diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index 048e3f581..d872997c4 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -17,13 +17,13 @@ Revision History: --*/ -#include "smt/smt_context.h" -#include "smt/theory_array_full.h" +#include "util/stats.h" #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" #include "ast/ast_util.h" #include "ast/ast_smt2_pp.h" -#include "util/stats.h" +#include "smt/smt_context.h" +#include "smt/theory_array_full.h" namespace smt { @@ -54,11 +54,9 @@ namespace smt { set_prop_upward(v,d); d_full->m_maps.push_back(s); m_trail_stack.push(push_back_trail(d_full->m_maps)); - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) { - SASSERT(is_select(*it)); - instantiate_select_map_axiom(*it, s); + for (enode* n : d->m_parent_selects) { + SASSERT(is_select(n)); + instantiate_select_map_axiom(n, s); } set_prop_upward(s); } @@ -67,15 +65,10 @@ namespace smt { bool result = false; var_data * d = m_var_data[v]; var_data_full * d_full = m_var_data_full[v]; - unsigned num_maps = d_full->m_parent_maps.size(); - unsigned num_selects = d->m_parent_selects.size(); - for (unsigned i = 0; i < num_maps; ++i) { - for (unsigned j = 0; j < num_selects; ++j) { - if (instantiate_select_map_axiom(d->m_parent_selects[j], d_full->m_parent_maps[i])) { - result = true; - } - } - } + for (enode* pm : d_full->m_parent_maps) + for (enode* ps : d->m_parent_selects) + if (instantiate_select_map_axiom(ps, pm)) + result = true; return result; } @@ -91,11 +84,9 @@ namespace smt { d_full->m_parent_maps.push_back(s); m_trail_stack.push(push_back_trail(d_full->m_parent_maps)); if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) { - if (!m_params.m_array_cg || (*it)->is_cgr()) { - instantiate_select_map_axiom(*it, s); + for (enode * n : d->m_parent_selects) { + if (!m_params.m_array_cg || n->is_cgr()) { + instantiate_select_map_axiom(n, s); } } } @@ -118,20 +109,14 @@ namespace smt { instantiate_axiom_map_for(v); } var_data_full * d2 = m_var_data_full[v]; - ptr_vector::iterator it = d->m_stores.begin(); - ptr_vector::iterator end = d->m_stores.end(); - for (; it != end; ++it) { - set_prop_upward(*it); + for (enode * n : d->m_stores) { + set_prop_upward(n); } - it = d2->m_maps.begin(); - end = d2->m_maps.end(); - for (; it != end; ++it) { - set_prop_upward(*it); + for (enode * n : d2->m_maps) { + set_prop_upward(n); } - it = d2->m_consts.begin(); - end = d2->m_consts.end(); - for (; it != end; ++it) { - set_prop_upward(*it); + for (enode * n : d2->m_consts) { + set_prop_upward(n); } } } @@ -180,12 +165,9 @@ namespace smt { m_trail_stack.push(push_back_trail(consts)); consts.push_back(cnst); instantiate_default_const_axiom(cnst); - - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) { - SASSERT(is_select(*it)); - instantiate_select_const_axiom(*it, cnst); + for (enode * n : d->m_parent_selects) { + SASSERT(is_select(n)); + instantiate_select_const_axiom(n, cnst); } } @@ -199,12 +181,9 @@ namespace smt { m_trail_stack.push(push_back_trail(as_arrays)); as_arrays.push_back(arr); instantiate_default_as_array_axiom(arr); - - ptr_vector::iterator it = d->m_parent_selects.begin(); - ptr_vector::iterator end = d->m_parent_selects.end(); - for (; it != end; ++it) { - SASSERT(is_select(*it)); - instantiate_select_as_array_axiom(*it, arr); + for (enode * n : d->m_parent_selects) { + SASSERT(is_select(n)); + instantiate_select_as_array_axiom(n, arr); } } @@ -257,6 +236,10 @@ namespace smt { } bool theory_array_full::internalize_term(app * n) { + context & ctx = get_context(); + if (ctx.e_internalized(n)) { + return true; + } TRACE("array", tout << mk_pp(n, get_manager()) << "\n";); if (is_store(n) || is_select(n)) { @@ -272,11 +255,10 @@ namespace smt { if (!internalize_term_core(n)) { return true; } - context & ctx = get_context(); if (is_map(n) || is_array_ext(n)) { - for (unsigned i = 0; i < n->get_num_args(); ++i) { - enode* arg = ctx.get_enode(n->get_arg(i)); + for (expr* e : *n) { + enode* arg = ctx.get_enode(e); if (!is_attached_to_var(arg)) { mk_var(arg); } @@ -300,8 +282,8 @@ namespace smt { add_parent_default(v_arg); } else if (is_map(n)) { - for (unsigned i = 0; i < n->get_num_args(); ++i) { - enode* arg = ctx.get_enode(n->get_arg(i)); + for (expr* e : *n) { + enode* arg = ctx.get_enode(e); theory_var v_arg = arg->get_th_var(get_id()); add_parent_map(v_arg, node); } @@ -334,27 +316,17 @@ namespace smt { // v1 is the new root SASSERT(v1 == find(v1)); var_data_full * d2 = m_var_data_full[v2]; - ptr_vector::iterator it, end; - - it = d2->m_maps.begin(); - end = d2->m_maps.end(); - for (; it != end; ++it) { - add_map(v1, *it); + for (enode * n : d2->m_maps) { + add_map(v1, n); } - it = d2->m_parent_maps.begin(); - end = d2->m_parent_maps.end(); - for (; it != end; ++it) { - add_parent_map(v1, *it); + for (enode * n : d2->m_parent_maps) { + add_parent_map(v1, n); } - it = d2->m_consts.begin(); - end = d2->m_consts.end(); - for (; it != end; ++it) { - add_const(v1, *it); + for (enode * n : d2->m_consts) { + add_const(v1, n); } - it = d2->m_as_arrays.begin(); - end = d2->m_as_arrays.end(); - for (; it != end; ++it) { - add_as_array(v1, *it); + for (enode * n : d2->m_as_arrays) { + add_as_array(v1, n); } TRACE("array", tout << mk_pp(get_enode(v1)->get_owner(), get_manager()) << "\n"; @@ -367,21 +339,13 @@ namespace smt { SASSERT(v != null_theory_var); v = find(v); var_data* d = m_var_data[v]; - ptr_vector::iterator it, end; - - it = d->m_stores.begin(); - end = d->m_stores.end(); - for(; it != end; ++it) { - enode * store = *it; + for (enode * store : d->m_stores) { SASSERT(is_store(store)); instantiate_default_store_axiom(store); } if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { - it = d->m_parent_stores.begin(); - end = d->m_parent_stores.end(); - for (; it != end; ++it) { - enode* store = *it; + for (enode * store : d->m_parent_stores) { SASSERT(is_store(store)); if (!m_params.m_array_cg || store->is_cgr()) { instantiate_default_store_axiom(store); @@ -399,23 +363,15 @@ namespace smt { v = find(v); var_data_full* d_full = m_var_data_full[v]; var_data* d = m_var_data[v]; - ptr_vector::iterator it = d_full->m_consts.begin(); - ptr_vector::iterator end = d_full->m_consts.end(); - for (; it != end; ++it) { - instantiate_select_const_axiom(s, *it); + for (enode * n : d_full->m_consts) { + instantiate_select_const_axiom(s, n); } - it = d_full->m_maps.begin(); - end = d_full->m_maps.end(); - for (; it != end; ++it) { - enode* map = *it; + for (enode * map : d_full->m_maps) { SASSERT(is_map(map)); instantiate_select_map_axiom(s, map); } if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { - it = d_full->m_parent_maps.begin(); - end = d_full->m_parent_maps.end(); - for (; it != end; ++it) { - enode* map = *it; + for (enode * map : d_full->m_parent_maps) { SASSERT(is_map(map)); if (!m_params.m_array_cg || map->is_cgr()) { instantiate_select_map_axiom(s, map); @@ -437,7 +393,7 @@ namespace smt { enode * arg = ctx.get_enode(n->get_arg(0)); theory_var v = arg->get_th_var(get_id()); SASSERT(v != null_theory_var); - add_parent_select(find(v), node); + add_parent_select(find(v), node); } else if (is_default(n)) { enode * arg = ctx.get_enode(n->get_arg(0)); @@ -577,7 +533,14 @@ namespace smt { return try_assign_eq(val, def); } + /** + * instantiate f(ep1,ep2,..,ep_n) = default(as-array f) + * it is disabled to avoid as-array terms during search. + */ + bool theory_array_full::instantiate_default_as_array_axiom(enode* arr) { + return false; +#if 0 context& ctx = get_context(); if (!ctx.add_fingerprint(this, 0, 1, &arr)) { return false; @@ -595,6 +558,7 @@ namespace smt { ctx.internalize(def, false); ctx.internalize(val.get(), false); return try_assign_eq(val.get(), def); +#endif } bool theory_array_full::has_large_domain(app* array_term) { diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b7aaff68a..42d90c242 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -843,14 +843,12 @@ namespace smt { context & ctx = get_context(); bool first = true; - ptr_vector::const_iterator it = ctx.begin_enodes(); - ptr_vector::const_iterator end = ctx.end_enodes(); - for (; it != end; it++) { - theory_var v = (*it)->get_th_var(get_family_id()); + for (enode* n : ctx.enodes()) { + theory_var v = n->get_th_var(get_family_id()); if (v != -1) { if (first) out << "fpa theory variables:" << std::endl; out << v << " -> " << - mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + mk_ismt2_pp(n->get_owner(), m) << std::endl; first = false; } } @@ -858,30 +856,24 @@ namespace smt { if (first) return; out << "bv theory variables:" << std::endl; - it = ctx.begin_enodes(); - end = ctx.end_enodes(); - for (; it != end; it++) { - theory_var v = (*it)->get_th_var(m_bv_util.get_family_id()); + for (enode * n : ctx.enodes()) { + theory_var v = n->get_th_var(m_bv_util.get_family_id()); if (v != -1) out << v << " -> " << - mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + mk_ismt2_pp(n->get_owner(), m) << std::endl; } out << "arith theory variables:" << std::endl; - it = ctx.begin_enodes(); - end = ctx.end_enodes(); - for (; it != end; it++) { - theory_var v = (*it)->get_th_var(m_arith_util.get_family_id()); + for (enode* n : ctx.enodes()) { + theory_var v = n->get_th_var(m_arith_util.get_family_id()); if (v != -1) out << v << " -> " << - mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + mk_ismt2_pp(n->get_owner(), m) << std::endl; } out << "equivalence classes:\n"; - it = ctx.begin_enodes(); - end = ctx.end_enodes(); - for (; it != end; ++it) { - expr * n = (*it)->get_owner(); - expr * r = (*it)->get_root()->get_owner(); - out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; + for (enode * n : ctx.enodes()) { + expr * e = n->get_owner(); + expr * r = n->get_root()->get_owner(); + out << r->get_id() << " --> " << mk_ismt2_pp(e, m) << std::endl; } } }; diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 9959780b7..0b5b98308 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -101,7 +101,7 @@ class elim_small_bv_tactic : public tactic { }); var_subst vsbst(m); - vsbst(e, substitution.size(), substitution.c_ptr(), res); + res = vsbst(e, substitution.size(), substitution.c_ptr()); SASSERT(is_well_sorted(m, res)); proof_ref pr(m); @@ -123,6 +123,9 @@ class elim_small_bv_tactic : public tactic { expr * const * new_no_patterns, expr_ref & result, proof_ref & result_pr) { + if (is_lambda(q)) { + return false; + } TRACE("elim_small_bv", tout << "reduce_quantifier " << mk_ismt2_pp(q, m) << std::endl; ); unsigned long long num_steps = 0; unsigned curr_sz = m_bindings.size(); @@ -158,8 +161,8 @@ class elim_small_bv_tactic : public tactic { for (unsigned k = 0; k < new_bodies.size(); k++) tout << mk_ismt2_pp(new_bodies[k].get(), m) << std::endl; ); - body = q->is_forall() ? m.mk_and(new_bodies.size(), new_bodies.c_ptr()) : - m.mk_or(new_bodies.size(), new_bodies.c_ptr()); + body = is_forall(q) ? m.mk_and(new_bodies.size(), new_bodies.c_ptr()) : + m.mk_or(new_bodies.size(), new_bodies.c_ptr()); SASSERT(is_well_sorted(m, body)); proof_ref pr(m); @@ -171,7 +174,7 @@ class elim_small_bv_tactic : public tactic { quantifier_ref new_q(m); new_q = m.update_quantifier(q, body); unused_vars_eliminator el(m, m_params); - el(new_q, result); + result = el(new_q); TRACE("elim_small_bv", tout << "elimination result: " << mk_ismt2_pp(result, m) << std::endl; ); diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 939541957..b3c6d0e24 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -109,10 +109,17 @@ protected: m_stats["quantifiers"]++; SASSERT(is_app(q->get_expr())); app * body = to_app(q->get_expr()); - if (q->is_forall()) + switch (q->get_kind()) { + case forall_k: m_stats["forall-variables"] += q->get_num_decls(); - else + break; + case exists_k: m_stats["exists-variables"] += q->get_num_decls(); + break; + case lambda_k: + m_stats["lambda-variables"] += q->get_num_decls(); + break; + } m_stats["patterns"] += q->get_num_patterns(); m_stats["no-patterns"] += q->get_num_no_patterns(); m_qdepth++; diff --git a/src/tactic/core/distribute_forall_tactic.cpp b/src/tactic/core/distribute_forall_tactic.cpp index 98c942432..c2688f741 100644 --- a/src/tactic/core/distribute_forall_tactic.cpp +++ b/src/tactic/core/distribute_forall_tactic.cpp @@ -31,7 +31,7 @@ class distribute_forall_tactic : public tactic { expr_ref & result, proof_ref & result_pr) { - if (!old_q->is_forall()) { + if (!is_forall(old_q)) { return false; } @@ -49,8 +49,7 @@ class distribute_forall_tactic : public tactic { expr * not_arg = m.mk_not(arg); quantifier_ref tmp_q(m); tmp_q = m.update_quantifier(old_q, not_arg); - expr_ref new_q(m); - elim_unused_vars(m, tmp_q, params_ref(), new_q); + expr_ref new_q = elim_unused_vars(m, tmp_q, params_ref()); new_args.push_back(new_q); } result = m.mk_and(new_args.size(), new_args.c_ptr()); @@ -69,8 +68,7 @@ class distribute_forall_tactic : public tactic { expr * arg = to_app(new_body)->get_arg(i); quantifier_ref tmp_q(m); tmp_q = m.update_quantifier(old_q, arg); - expr_ref new_q(m); - elim_unused_vars(m, tmp_q, params_ref(), new_q); + expr_ref new_q = elim_unused_vars(m, tmp_q, params_ref()); new_args.push_back(new_q); } result = m.mk_and(new_args.size(), new_args.c_ptr()); diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 27a5bdc94..87a480bdb 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -337,12 +337,14 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { } args.reverse(); } + pop(scope_level() - old_lvl); r = is_and ? mk_and(args) : mk_or(args); return r; } + bool dom_simplify_tactic::init(goal& g) { expr_ref_vector args(m); unsigned sz = g.size(); diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index eb3500729..caca89afc 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -5,6 +5,7 @@ Module Name: dom_simplify_tactic.cpp + Abstract: Dominator-based context simplifer. diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 64947eca0..69e5b4cee 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -79,11 +79,11 @@ class injectivity_tactic : public tactic { ast_manager & m() const { return m_manager; } bool is_axiom(expr* n, func_decl* &f, func_decl* &g) { - if (!is_quantifier(n)) + if (!is_forall(n)) return false; quantifier* const q = to_quantifier(n); - if (!q->is_forall() || q->get_num_decls() != 1) + if (q->get_num_decls() != 1) return false; const expr * const body = q->get_expr(); diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index b29a80927..929168ed0 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -474,7 +474,6 @@ class tseitin_cnf_tactic : public tactic { bool sign = m.is_not(_b, _b); if (!m.is_or(_b)) return NO; app* b = to_app(_b); - unsigned num = b->get_num_args(); if (first) { bool visited = true; visit(a, visited); diff --git a/src/tactic/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp index eeb2967f2..fa3e82e64 100644 --- a/src/tactic/horn_subsume_model_converter.cpp +++ b/src/tactic/horn_subsume_model_converter.cpp @@ -96,8 +96,7 @@ bool horn_subsume_model_converter::mk_horn( // substitute variables directly. if (!subst.empty()) { - expr_ref tmp(body_expr); - vs(tmp, subst.size(), subst.c_ptr(), body_expr); + body_expr = vs(body_expr, subst.size(), subst.c_ptr()); } if (fv.empty()) { @@ -123,7 +122,7 @@ bool horn_subsume_model_converter::mk_horn( // formula is closed. DEBUG_CODE(expr_free_vars fv; fv(clause); SASSERT(fv.empty());); - while (is_quantifier(clause) && to_quantifier(clause)->is_forall()) { + while (is_quantifier(clause) && to_quantifier(clause)->get_kind() == forall_k) { quantifier* q = to_quantifier(clause); clause = q->get_expr(); } diff --git a/src/tactic/sine_filter.cpp b/src/tactic/sine_filter.cpp index 647791784..b1db12964 100644 --- a/src/tactic/sine_filter.cpp +++ b/src/tactic/sine_filter.cpp @@ -177,7 +177,7 @@ private: } else if (is_quantifier(curr.first)) { quantifier *q = to_quantifier(curr.first); - if (q->is_forall()) { + if (is_forall(q)) { if (q->has_patterns()) { ptr_vector next_consts; if (quantifier_matches(q, consts, next_consts)) { @@ -199,7 +199,7 @@ private: stack.push_back(work_item(q->get_expr(), curr.second)); } } - else if (q->is_exists()) { + else if (is_exists(q)) { stack.push_back(work_item(q->get_expr(), curr.second)); } } diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index 875ef2edb..ee8a4605b 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -52,7 +52,7 @@ ufbv_rewriter::~ufbv_rewriter() { bool ufbv_rewriter::is_demodulator(expr * e, expr_ref & large, expr_ref & small) const { if (e->get_kind() == AST_QUANTIFIER) { quantifier * q = to_quantifier(e); - if (q->is_forall()) { + if (is_forall(q)) { expr * qe = q->get_expr(); if ((m_manager.is_eq(qe) || m_manager.is_iff(qe))) { app * eq = to_app(q->get_expr()); @@ -439,8 +439,7 @@ expr * ufbv_rewriter::rewrite(expr * n) { quantifier_ref q(m_manager); q = m_manager.update_quantifier(to_quantifier(actual), new_body); m_new_exprs.push_back(q); - expr_ref new_q(m_manager); - elim_unused_vars(m_manager, q, params_ref(), new_q); + expr_ref new_q = elim_unused_vars(m_manager, q, params_ref()); m_new_exprs.push_back(new_q); rewrite_cache(e, new_q, true); m_rewrite_todo.pop_back(); diff --git a/src/test/quant_solve.cpp b/src/test/quant_solve.cpp index ac334c718..04a75c42e 100644 --- a/src/test/quant_solve.cpp +++ b/src/test/quant_solve.cpp @@ -147,7 +147,7 @@ static void parse_fml(char const* str, app_ref_vector& vars, expr_ref& fml) { } fml = q->get_expr(); var_subst vs(m, true); - vs(fml, vars.size(), (expr*const*)vars.c_ptr(), fml); + fml = vs(fml, vars.size(), (expr*const*)vars.c_ptr()); } } diff --git a/src/test/var_subst.cpp b/src/test/var_subst.cpp index 09535ae8c..068e29930 100644 --- a/src/test/var_subst.cpp +++ b/src/test/var_subst.cpp @@ -50,8 +50,7 @@ void tst_instantiate(ast_manager & m, expr * f) { expr_ref_vector cnsts(m); for (unsigned i = 0; i < q->get_num_decls(); i++) cnsts.push_back(m.mk_fresh_const("a", q->get_decl_sort(i))); - expr_ref r(m); - instantiate(m, q, cnsts.c_ptr(), r); + expr_ref r = instantiate(m, q, cnsts.c_ptr()); TRACE("var_subst", tout << "quantifier:\n" << mk_pp(q, m) << "\nresult:\n" << mk_pp(r, m) << "\n";); } } @@ -83,7 +82,7 @@ void tst_subst(ast_manager& m) { sub1.push_back(x); sub1.push_back(y); // replace #1 -> #2, #2 -> #1 - subst(e2, 2, sub1.c_ptr(), e3); + e3 = subst(e2, 2, sub1.c_ptr()); std::cout << mk_pp(e2, m) << "\n"; std::cout << mk_pp(e3, m) << "\n"; std::cout << mk_pp(t1, m) << "\n"; @@ -91,7 +90,7 @@ void tst_subst(ast_manager& m) { // replace #2 -> #3, #3 -> #2 e2 = m.mk_forall(2, ss, names, e1); - subst(e2, 2, sub1.c_ptr(), e3); + e3 = subst(e2, 2, sub1.c_ptr()); std::cout << mk_pp(e2, m) << "\n"; std::cout << mk_pp(e3, m) << "\n"; std::cout << mk_pp(t2, m) << "\n"; diff --git a/src/util/plugin_manager.h b/src/util/plugin_manager.h index 2c4223eeb..4bf04da34 100644 --- a/src/util/plugin_manager.h +++ b/src/util/plugin_manager.h @@ -58,6 +58,8 @@ public: return m_fid2plugins.get(fid, 0); } + ptr_vector const& plugins() const { return m_plugins; } + typename ptr_vector::const_iterator begin() const { return m_plugins.begin(); } diff --git a/src/util/top_sort.h b/src/util/top_sort.h index 5f7db9c3e..f529d8a44 100644 --- a/src/util/top_sort.h +++ b/src/util/top_sort.h @@ -75,7 +75,7 @@ class top_sort { public: - ~top_sort() { + virtual ~top_sort() { for (auto & kv : m_deps) dealloc(kv.m_value); } @@ -96,6 +96,20 @@ public: } ptr_vector const& top_sorted() { return m_top_sorted; } + + obj_map const& partition_ids() const { return m_partition_id; } + + unsigned partition_id(T* t) const { return m_partition_id[t]; } + + bool is_singleton_partition(T* f) const { + unsigned pid = m_partition_id[f]; + return f == m_top_sorted[pid] && + (pid == 0 || m_partition_id[m_top_sorted[pid-1]] != pid) && + (pid + 1 == m_top_sorted.size() || m_partition_id[m_top_sorted[pid+1]] != pid); + } + + obj_map const& deps() const { return m_deps; } + }; #endif /* TOP_SORT_H_ */