From 10cd396ae3ad8439448175f9957e2e962aa6e04c Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 31 Aug 2017 17:21:44 -0400 Subject: [PATCH 01/57] rewriter patch for theory_str --- src/smt/theory_str.cpp | 84 +++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 47 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 89e0123a8..0ddf24596 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -14,17 +14,17 @@ Revision History: --*/ -#include"ast_smt2_pp.h" -#include"smt_context.h" -#include"theory_str.h" -#include"smt_model_generator.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" +#include "smt/smt_context.h" +#include "smt/theory_str.h" +#include "smt/smt_model_generator.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" #include #include -#include"theory_seq_empty.h" -#include"theory_arith.h" -#include"ast_util.h" +#include "smt/theory_seq_empty.h" +#include "smt/theory_arith.h" +#include "ast/ast_util.h" namespace smt { @@ -166,14 +166,18 @@ namespace smt { } } - void theory_str::assert_axiom(expr * e) { + void theory_str::assert_axiom(expr * _e) { if (opt_VerifyFinalCheckProgress) { finalCheckProgressIndicator = true; } - if (get_manager().is_true(e)) return; - TRACE("str", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << std::endl;); + if (get_manager().is_true(_e)) return; context & ctx = get_context(); + ast_manager& m = get_manager(); + TRACE("str", tout << "asserting " << mk_ismt2_pp(_e, m) << std::endl;); + expr_ref e(_e, m); + th_rewriter rw(m); + rw(e); if (!ctx.b_internalized(e)) { ctx.internalize(e, false); } @@ -1419,6 +1423,9 @@ namespace smt { void theory_str::instantiate_axiom_Substr(enode * e) { context & ctx = get_context(); ast_manager & m = get_manager(); + expr* substrBase = 0; + expr* substrPos = 0; + expr* substrLen = 0; app * expr = e->get_owner(); if (axiomatized_terms.contains(expr)) { @@ -1429,12 +1436,7 @@ namespace smt { TRACE("str", tout << "instantiate Substr axiom for " << mk_pp(expr, m) << std::endl;); - expr_ref substrBase(expr->get_arg(0), m); - expr_ref substrPos(expr->get_arg(1), m); - expr_ref substrLen(expr->get_arg(2), m); - SASSERT(substrBase); - SASSERT(substrPos); - SASSERT(substrLen); + VERIFY(u.str.is_extract(expr, substrBase, substrPos, substrLen)); expr_ref zero(m_autil.mk_numeral(rational::zero(), true), m); expr_ref minusOne(m_autil.mk_numeral(rational::minus_one(), true), m); @@ -1452,28 +1454,19 @@ namespace smt { // len >= 0 argumentsValid_terms.push_back(m_autil.mk_ge(substrLen, zero)); - expr_ref argumentsValid(mk_and(argumentsValid_terms), m); - SASSERT(argumentsValid); - ctx.internalize(argumentsValid, false); // (pos+len) >= strlen(base) // --> pos + len + -1*strlen(base) >= 0 expr_ref lenOutOfBounds(m_autil.mk_ge( m_autil.mk_add(substrPos, substrLen, m_autil.mk_mul(minusOne, mk_strlen(substrBase))), zero), m); - SASSERT(lenOutOfBounds); - ctx.internalize(argumentsValid, false); + expr_ref argumentsValid = mk_and(argumentsValid_terms); // Case 1: pos < 0 or pos >= strlen(base) or len < 0 // ==> (Substr ...) = "" expr_ref case1_premise(m.mk_not(argumentsValid), m); - SASSERT(case1_premise); - ctx.internalize(case1_premise, false); expr_ref case1_conclusion(ctx.mk_eq_atom(expr, mk_string("")), m); - SASSERT(case1_conclusion); - ctx.internalize(case1_conclusion, false); - expr_ref case1(rewrite_implication(case1_premise, case1_conclusion), m); - SASSERT(case1); + expr_ref case1(m.mk_implies(case1_premise, case1_conclusion), m); // Case 2: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) >= strlen(base) // ==> base = t0.t1 AND len(t0) = pos AND (Substr ...) = t1 @@ -1483,8 +1476,7 @@ namespace smt { ctx.mk_eq_atom(substrBase, mk_concat(t0,t1)), ctx.mk_eq_atom(mk_strlen(t0), substrPos), ctx.mk_eq_atom(expr, t1)), m); - expr_ref case2(rewrite_implication(m.mk_and(argumentsValid, lenOutOfBounds), case2_conclusion), m); - SASSERT(case2); + expr_ref case2(m.mk_implies(m.mk_and(argumentsValid, lenOutOfBounds), case2_conclusion), m); // Case 3: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) < strlen(base) // ==> base = t2.t3.t4 AND len(t2) = pos AND len(t3) = len AND (Substr ...) = t3 @@ -1497,16 +1489,11 @@ namespace smt { case3_conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(t3), substrLen)); case3_conclusion_terms.push_back(ctx.mk_eq_atom(expr, t3)); expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m); - expr_ref case3(rewrite_implication(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); - SASSERT(case3); + expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); - ctx.internalize(case1, false); - ctx.internalize(case2, false); - ctx.internalize(case3, false); - - expr_ref finalAxiom(m.mk_and(case1, case2, case3), m); - SASSERT(finalAxiom); - assert_axiom(finalAxiom); + assert_axiom(case1); + assert_axiom(case2); + assert_axiom(case3); } void theory_str::instantiate_axiom_Replace(enode * e) { @@ -1549,14 +1536,12 @@ namespace smt { expr_ref elseBranch(ctx.mk_eq_atom(result, expr->get_arg(0)), m); expr_ref breakdownAssert(m.mk_ite(condAst, m.mk_and(thenItems.size(), thenItems.c_ptr()), elseBranch), m); + assert_axiom(breakdownAssert); + SASSERT(breakdownAssert); expr_ref reduceToResult(ctx.mk_eq_atom(expr, result), m); - SASSERT(reduceToResult); - - expr_ref finalAxiom(m.mk_and(breakdownAssert, reduceToResult), m); - SASSERT(finalAxiom); - assert_axiom(finalAxiom); + assert_axiom(reduceToResult); } void theory_str::instantiate_axiom_str_to_int(enode * e) { @@ -4658,7 +4643,7 @@ namespace smt { // safety if (!ctx.e_internalized(e)) { - return false; + return false; } // if an integer constant exists in the eqc, it should be the root @@ -8422,6 +8407,7 @@ namespace smt { // Check agreement between integer and string theories for the term a = (str.to-int S). // Returns true if axioms were added, and false otherwise. bool theory_str::finalcheck_str2int(app * a) { + SASSERT(u.str.is_stoi(a)); bool axiomAdd = false; context & ctx = get_context(); ast_manager & m = get_manager(); @@ -8448,7 +8434,11 @@ namespace smt { } } else { TRACE("str", tout << "integer theory has no assignment for " << mk_pp(a, m) << std::endl;); - NOT_IMPLEMENTED_YET(); + expr_ref is_zero(ctx.mk_eq_atom(a, m_autil.mk_int(0)), m); + literal is_zero_l = mk_literal(is_zero); + axiomAdd = true; + TRACE("str", ctx.display(tout);); + // NOT_IMPLEMENTED_YET(); } return axiomAdd; From 4e4c72580b29d57d376fb425d49f9f397a539cd3 Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 7 Sep 2017 14:06:37 -0400 Subject: [PATCH 02/57] don't rewrite on every axiom in theory_str --- src/smt/theory_str.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0ddf24596..f59c06fae 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -176,8 +176,8 @@ namespace smt { ast_manager& m = get_manager(); TRACE("str", tout << "asserting " << mk_ismt2_pp(_e, m) << std::endl;); expr_ref e(_e, m); - th_rewriter rw(m); - rw(e); + //th_rewriter rw(m); + //rw(e); if (!ctx.b_internalized(e)) { ctx.internalize(e, false); } @@ -1491,9 +1491,21 @@ namespace smt { expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m); expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); - assert_axiom(case1); - assert_axiom(case2); - assert_axiom(case3); + { + th_rewriter rw(m); + + expr_ref case1_rw(case1, m); + rw(case1_rw); + assert_axiom(case1_rw); + + expr_ref case2_rw(case2, m); + rw(case2_rw); + assert_axiom(case2_rw); + + expr_ref case3_rw(case3, m); + rw(case3_rw); + assert_axiom(case3_rw); + } } void theory_str::instantiate_axiom_Replace(enode * e) { From 1ce68b3794d9bac95383d3f915bf0f2819ee22de Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Thu, 7 Sep 2017 14:53:34 -0400 Subject: [PATCH 03/57] rewrite theory_str replace instances --- src/smt/theory_str.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index f59c06fae..0322b736d 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1547,13 +1547,17 @@ namespace smt { // false branch expr_ref elseBranch(ctx.mk_eq_atom(result, expr->get_arg(0)), m); + th_rewriter rw(m); + expr_ref breakdownAssert(m.mk_ite(condAst, m.mk_and(thenItems.size(), thenItems.c_ptr()), elseBranch), m); - assert_axiom(breakdownAssert); - - SASSERT(breakdownAssert); + expr_ref breakdownAssert_rw(breakdownAssert, m); + rw(breakdownAssert_rw); + assert_axiom(breakdownAssert_rw); expr_ref reduceToResult(ctx.mk_eq_atom(expr, result), m); - assert_axiom(reduceToResult); + expr_ref reduceToResult_rw(reduceToResult, m); + rw(reduceToResult_rw); + assert_axiom(reduceToResult_rw); } void theory_str::instantiate_axiom_str_to_int(enode * e) { From 45c60ed55cdcf2ed18dd4ae0ace1043bc04e40b5 Mon Sep 17 00:00:00 2001 From: Adrian Stanciu Date: Wed, 18 Oct 2017 14:50:44 +0300 Subject: [PATCH 04/57] Update README.md Corrected path to Z3 Python interface --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 701556cc8..70956d439 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ utility is used to install ``Microsoft.Z3.dll`` into the [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file (``Microsoft.Z3.Sharp.pc``) is also installed which allows the [MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running -``make uninstall`` will remove the dll from the GAC and the pkg-config file. +``make uninstall`` will remove the dll from the GAC and the ``pkg-config`` file. See [``examples/dotnet``](examples/dotnet) for examples. @@ -170,8 +170,8 @@ If you do need to install to a non standard prefix a better approach is to use a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/) and install Z3 there. Python packages also work for Python3. Under Windows, recall to build inside the Visual C++ native command build environment. -Note that the buit/python/z3 directory should be accessible from where python is used with Z3 -and it depends on libz3.dll to be in the path. +Note that the ``build/python/z3`` directory should be accessible from where python is used with Z3 +and it depends on ``libz3.dll`` to be in the path. ```bash virtualenv venv From c9f540b066a33196f47b379d95327d84f55ffacf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Oct 2017 11:08:48 -0700 Subject: [PATCH 05/57] additional array functions exposed over API, ping #1223 Signed-off-by: Nikolaj Bjorner --- src/api/api_array.cpp | 88 +++++++++++++++++++++++++- src/api/c++/z3++.h | 28 +++++++++ src/api/dotnet/ArraySort.cs | 7 +++ src/api/dotnet/Context.cs | 89 ++++++++++++++++++++++++--- src/api/java/ArraySort.java | 6 ++ src/api/java/Context.java | 64 ++++++++++++++++++- src/api/z3_api.h | 38 ++++++++++++ src/ast/array_decl_plugin.cpp | 12 +++- src/ast/array_decl_plugin.h | 6 +- src/ast/fpa/bv2fpa_converter.cpp | 2 +- src/smt/theory_array.cpp | 67 +++++++------------- src/smt/theory_array_base.cpp | 5 +- src/tactic/bv/bvarray2uf_rewriter.cpp | 14 ++--- 13 files changed, 354 insertions(+), 72 deletions(-) diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index a5916e987..5e6764dff 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -34,6 +34,19 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const* domain, Z3_sort range) { + Z3_TRY; + LOG_Z3_mk_array_sort_n(c, n, domain, range); + RESET_ERROR_CODE(); + vector params; + for (unsigned i = 0; i < n; ++i) params.push_back(parameter(to_sort(domain[i]))); + params.push_back(parameter(to_sort(range))); + sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, params.size(), params.c_ptr()); + mk_c(c)->save_ast_trail(ty); + RETURN_Z3(of_sort(ty)); + Z3_CATCH_RETURN(0); + } + 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); @@ -57,6 +70,35 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs) { + Z3_TRY; + LOG_Z3_mk_select_n(c, a, n, idxs); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + expr * _a = to_expr(a); + // expr * _i = to_expr(i); + sort * a_ty = m.get_sort(_a); + // sort * i_ty = m.get_sort(_i); + if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { + SET_ERROR_CODE(Z3_SORT_ERROR); + RETURN_Z3(0); + } + ptr_vector domain; + ptr_vector args; + args.push_back(_a); + domain.push_back(a_ty); + for (unsigned i = 0; i < n; ++i) { + args.push_back(to_expr(idxs[i])); + domain.push_back(m.get_sort(to_expr(idxs[i]))); + } + func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_SELECT, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr()); + app * r = m.mk_app(d, args.size(), args.c_ptr()); + mk_c(c)->save_ast_trail(r); + check_sorts(c, r); + RETURN_Z3(of_ast(r)); + Z3_CATCH_RETURN(0); + } + 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); @@ -82,6 +124,37 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v) { + Z3_TRY; + LOG_Z3_mk_store_n(c, a, n, idxs, v); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + expr * _a = to_expr(a); + expr * _v = to_expr(v); + sort * a_ty = m.get_sort(_a); + sort * v_ty = m.get_sort(_v); + if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { + SET_ERROR_CODE(Z3_SORT_ERROR); + RETURN_Z3(0); + } + ptr_vector domain; + ptr_vector args; + args.push_back(_a); + domain.push_back(a_ty); + for (unsigned i = 0; i < n; ++i) { + args.push_back(to_expr(idxs[i])); + domain.push_back(m.get_sort(to_expr(idxs[i]))); + } + args.push_back(_v); + domain.push_back(v_ty); + func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_STORE, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr()); + app * r = m.mk_app(d, args.size(), args.c_ptr()); + mk_c(c)->save_ast_trail(r); + check_sorts(c, r); + RETURN_Z3(of_ast(r)); + Z3_CATCH_RETURN(0); + } + 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); @@ -188,6 +261,18 @@ extern "C" { MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP); MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP); + Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f) { + Z3_TRY; + LOG_Z3_mk_as_array(c, f); + RESET_ERROR_CODE(); + ast_manager & m = mk_c(c)->m(); + array_util a(m); + app * r = a.mk_as_array(to_func_decl(f)); + mk_c(c)->save_ast_trail(r); + return of_ast(r); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) { return Z3_mk_select(c, set, elem); } @@ -222,7 +307,8 @@ extern "C" { CHECK_VALID_AST(t, 0); if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && to_sort(t)->get_decl_kind() == ARRAY_SORT) { - Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(1).get_ast()); + unsigned n = to_sort(t)->get_num_parameters(); + Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(n-1).get_ast()); RETURN_Z3(r); } SET_ERROR_CODE(Z3_INVALID_ARG); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index f55ece034..23a7bd22e 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -250,6 +250,8 @@ namespace z3 { Example: Given a context \c c, c.array_sort(c.int_sort(), c.bool_sort()) is an array sort from integer to Boolean. */ 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, @@ -2327,6 +2329,11 @@ namespace z3 { inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); } inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); } + inline sort context::array_sort(sort_vector const& d, sort r) { + 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]); } @@ -2573,11 +2580,32 @@ namespace z3 { a.check_error(); return expr(a.ctx(), r); } + inline expr select(expr const & a, expr_vector const & i) { + check_context(a, i); + array idxs(i); + Z3_ast r = Z3_mk_select_n(a.ctx(), a, idxs.size(), idxs.ptr()); + 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) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range())); } + inline expr store(expr const & a, expr_vector const & i, expr const & v) { + check_context(a, i); check_context(a, v); + array idxs(i); + Z3_ast r = Z3_mk_store_n(a.ctx(), a, idxs.size(), idxs.ptr(), v); + a.check_error(); + return expr(a.ctx(), r); + } + + inline expr as_array(func_decl & f) { + Z3_ast r = Z3_mk_as_array(f.ctx(), f); + f.check_error(); + return expr(f.ctx(), r); + } #define MK_EXPR1(_fn, _arg) \ Z3_ast r = _fn(_arg.ctx(), _arg); \ diff --git a/src/api/dotnet/ArraySort.cs b/src/api/dotnet/ArraySort.cs index ddd27785c..47a73ae1f 100644 --- a/src/api/dotnet/ArraySort.cs +++ b/src/api/dotnet/ArraySort.cs @@ -63,6 +63,13 @@ namespace Microsoft.Z3 Contract.Requires(domain != null); Contract.Requires(range != null); } + internal ArraySort(Context ctx, Sort[] domain, Sort range) + : base(ctx, Native.Z3_mk_array_sort_n(ctx.nCtx, (uint)domain.Length, AST.ArrayToNative(domain), range.NativeObject)) + { + Contract.Requires(ctx != null); + Contract.Requires(domain != null); + Contract.Requires(range != null); + } #endregion }; diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index d7699c961..27711be81 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -274,6 +274,20 @@ namespace Microsoft.Z3 return new ArraySort(this, domain, range); } + /// + /// Create a new n-ary array sort. + /// + public ArraySort MkArraySort(Sort[] domain, Sort range) + { + Contract.Requires(domain != null); + Contract.Requires(range != null); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(domain); + CheckContextMatch(range); + return new ArraySort(this, domain, range); + } + /// /// Create a new tuple sort. /// @@ -2113,6 +2127,7 @@ namespace Microsoft.Z3 return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); } + /// /// Array read. /// @@ -2123,8 +2138,8 @@ namespace Microsoft.Z3 /// The node a must have an array sort [domain -> range], /// and i must have the sort domain. /// The sort of the result is range. - /// - /// + /// + /// /// public Expr MkSelect(ArrayExpr a, Expr i) { @@ -2137,6 +2152,30 @@ namespace Microsoft.Z3 return Expr.Create(this, Native.Z3_mk_select(nCtx, a.NativeObject, i.NativeObject)); } + /// + /// Array read. + /// + /// + /// The argument a is the array and args are the indices + /// of the array that gets read. + /// + /// The node a must have an array sort [domain1,..,domaink -> range], + /// and args must have the sort domain1,..,domaink. + /// The sort of the result is range. + /// + /// + /// + public Expr MkSelect(ArrayExpr a, params Expr[] args) + { + Contract.Requires(a != null); + Contract.Requires(args != null && Contract.ForAll(args, n => n != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(a); + CheckContextMatch(args); + return Expr.Create(this, Native.Z3_mk_select_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args))); + } + /// /// Array update. /// @@ -2151,8 +2190,9 @@ namespace Microsoft.Z3 /// on all indices except for i, where it maps to v /// (and the select of a with /// respect to i may be a different value). - /// - /// + /// + /// + /// /// public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v) { @@ -2167,14 +2207,45 @@ namespace Microsoft.Z3 return new ArrayExpr(this, Native.Z3_mk_store(nCtx, a.NativeObject, i.NativeObject, v.NativeObject)); } + /// + /// Array update. + /// + /// + /// The node a must have an array sort [domain1,..,domaink -> range], + /// args must have sort domain1,..,domaink, + /// v must have sort range. The sort of the result is [domain -> range]. + /// The semantics of this function is given by the theory of arrays described in the SMT-LIB + /// standard. See http://smtlib.org for more details. + /// The result of this function is an array that is equal to a + /// (with respect to select) + /// on all indices except for args, where it maps to v + /// (and the select of a with + /// respect to args may be a different value). + /// + /// + /// + /// + public ArrayExpr MkStore(ArrayExpr a, Expr[] args, Expr v) + { + Contract.Requires(a != null); + Contract.Requires(args != null); + Contract.Requires(v != null); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(args); + CheckContextMatch(a); + CheckContextMatch(v); + return new ArrayExpr(this, Native.Z3_mk_store_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args), v.NativeObject)); + } + /// /// Create a constant array. /// /// /// The resulting term is an array, such that a selecton an arbitrary index /// produces the value v. - /// - /// + /// + /// /// public ArrayExpr MkConstArray(Sort domain, Expr v) { @@ -2194,9 +2265,9 @@ namespace Microsoft.Z3 /// Eeach element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. - /// - /// - /// + /// + /// + /// /// public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args) { diff --git a/src/api/java/ArraySort.java b/src/api/java/ArraySort.java index 1574823d1..db4d992ed 100644 --- a/src/api/java/ArraySort.java +++ b/src/api/java/ArraySort.java @@ -56,4 +56,10 @@ public class ArraySort extends Sort super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(), range.getNativeObject())); } + + ArraySort(Context ctx, Sort[] domains, Sort range) + { + super(ctx, Native.mkArraySortN(ctx.nCtx(), domains.length, AST.arrayToNative(domains), + range.getNativeObject())); + } }; diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 72866a0ba..76303d670 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -224,6 +224,17 @@ public class Context implements AutoCloseable { return new ArraySort(this, domain, range); } + + /** + * Create a new array sort. + **/ + public ArraySort mkArraySort(Sort[] domains, Sort range) + { + checkContextMatch(domains); + checkContextMatch(range); + return new ArraySort(this, domains, range); + } + /** * Create a new string sort **/ @@ -414,7 +425,7 @@ public class Context implements AutoCloseable { * that is passed in as argument is updated with value v, * the remaining fields of t are unchanged. **/ - public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) + public Expr mkUpdateField(FuncDecl field, Expr t, Expr v) throws Z3Exception { return Expr.create (this, @@ -706,7 +717,7 @@ public class Context implements AutoCloseable { } /** - * Mk an expression representing {@code not(a)}. + * Create an expression representing {@code not(a)}. **/ public BoolExpr mkNot(BoolExpr a) { @@ -1679,6 +1690,28 @@ public class Context implements AutoCloseable { i.getNativeObject())); } + /** + * Array read. + * Remarks: The argument {@code a} is the array and + * {@code args} are the indices of the array that gets read. + * + * The node {@code a} must have an array sort + * {@code [domains -> range]}, and {@code args} must have the sorts + * {@code domains}. The sort of the result is {@code range}. + * + * @see #mkArraySort + * @see #mkStore + + **/ + public Expr mkSelect(ArrayExpr a, Expr[] args) + { + checkContextMatch(a); + checkContextMatch(args); + return Expr.create( + this, + Native.mkSelectN(nCtx(), a.getNativeObject(), args.length, AST.arrayToNative(args))); + } + /** * Array update. * Remarks: The node {@code a} must have an array sort @@ -1704,6 +1737,31 @@ public class Context implements AutoCloseable { i.getNativeObject(), v.getNativeObject())); } + /** + * Array update. + * Remarks: The node {@code a} must have an array sort + * {@code [domains -> range]}, {@code i} must have sort + * {@code domain}, {@code v} must have sort range. The sort of the + * result is {@code [domains -> range]}. The semantics of this function + * is given by the theory of arrays described in the SMT-LIB standard. See + * http://smtlib.org for more details. The result of this function is an + * array that is equal to {@code a} (with respect to + * {@code select}) on all indices except for {@code args}, where it + * maps to {@code v} (and the {@code select} of {@code a} + * with respect to {@code args} may be a different value). + * @see #mkArraySort + * @see #mkSelect + + **/ + public ArrayExpr mkStore(ArrayExpr a, Expr[] args, Expr v) + { + checkContextMatch(a); + checkContextMatch(args); + checkContextMatch(v); + return new ArrayExpr(this, Native.mkStoreN(nCtx(), a.getNativeObject(), + args.length, AST.arrayToNative(args), v.getNativeObject())); + } + /** * Create a constant array. * Remarks: The resulting term is an array, such @@ -2104,7 +2162,7 @@ public class Context implements AutoCloseable { /** * Create a range expression. */ - public ReExpr MkRange(SeqExpr lo, SeqExpr hi) + public ReExpr mkRange(SeqExpr lo, SeqExpr hi) { checkContextMatch(lo, hi); return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 154b8eb3c..9f155b45e 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1881,6 +1881,17 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range); + /** + \brief Create an array type with N arguments + + \sa Z3_mk_select_n + \sa Z3_mk_store_n + + def_API('Z3_mk_array_sort_n', SORT, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in(SORT))) + */ + 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. @@ -2973,6 +2984,15 @@ 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. + + def_API('Z3_mk_select_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST))) + + */ + Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs); + /** \brief Array update. @@ -2991,6 +3011,14 @@ 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. + + def_API('Z3_mk_store_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST), _in(AST))) + + */ + Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v); + /** \brief Create the constant array. @@ -3031,6 +3059,15 @@ extern "C" { def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST))) */ Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array); + + /** + \brief Create array with the same interpretation as a function. + The array satisfies the property (f x) = (select (_ as-array f) x) + for every argument x. + + def_API('Z3_mk_as_array', AST, (_in(CONTEXT), _in(FUNC_DECL))) + */ + Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f); /*@}*/ /** @name Sets */ @@ -3854,6 +3891,7 @@ extern "C" { /** \brief Return the domain of the given array sort. + In the case of a multi-dimensional array, this function returns the sort of the first dimension. \pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index cb016e263..0cc4f6031 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -242,7 +242,9 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) { parameter const* parameters = s->get_parameters(); if (num_parameters != arity) { - m_manager->raise_exception("select requires as many arguments as the size of the domain"); + std::stringstream strm; + strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments"; + m_manager->raise_exception(strm.str().c_str()); return 0; } ptr_buffer new_domain; // we need this because of coercions. @@ -314,7 +316,7 @@ func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domai return 0; } sort * r = to_sort(s->get_parameter(i).get_ast()); - parameter param(s); + parameter param(i); return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, ¶m)); } @@ -592,3 +594,9 @@ sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* rang params.push_back(parameter(range)); return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr()); } + +func_decl* array_util::mk_array_ext(sort *domain, unsigned i) { + sort * domains[2] = { domain, domain }; + parameter p(i); + return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains); +} diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 0704fe56a..1257ab2c6 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -143,6 +143,7 @@ public: bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); } bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } + bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); } bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); } @@ -182,12 +183,15 @@ public: return mk_const_array(s, m_manager.mk_true()); } + func_decl * mk_array_ext(sort* domain, unsigned i); + sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range); - app * mk_as_array(sort * s, func_decl * f) { + app * mk_as_array(func_decl * f) { parameter param(f); + sort * s = f->get_range(); return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, s); } }; diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index 93bd79571..2f5a7c3c1 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -250,7 +250,7 @@ bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_ am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); am.bv_fd = bv_f; - am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); + am.result = arr_util.mk_as_array(am.new_float_fd); return am; } diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 18fc9f50b..b8f76f9ad 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -53,18 +53,12 @@ namespace smt { var_data * d2 = m_var_data[v2]; if (!d1->m_prop_upward && d2->m_prop_upward) set_prop_upward(v1); - ptr_vector::iterator it = d2->m_stores.begin(); - ptr_vector::iterator end = d2->m_stores.end(); - for (; it != end; ++it) - add_store(v1, *it); - it = d2->m_parent_stores.begin(); - end = d2->m_parent_stores.end(); - for (; it != end; ++it) - add_parent_store(v1, *it); - it = d2->m_parent_selects.begin(); - end = d2->m_parent_selects.end(); - for (; it != end; ++it) - add_parent_select(v1, *it); + for (enode* n : d2->m_stores) + add_store(v1, n); + for (enode* n : d2->m_parent_stores) + add_parent_store(v1, n); + for (enode* n : d2->m_parent_selects) + add_parent_select(v1, n); TRACE("array", tout << "after merge\n"; display_var(tout, v1);); } @@ -103,16 +97,11 @@ namespace smt { d->m_parent_selects.push_back(s); TRACE("array", tout << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";); m_trail_stack.push(push_back_trail(d->m_parent_selects)); - ptr_vector::iterator it = d->m_stores.begin(); - ptr_vector::iterator end = d->m_stores.end(); - for (; it != end; ++it) { - instantiate_axiom2a(s, *it); + for (enode* n : d->m_stores) { + instantiate_axiom2a(s, n); } 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_axiom2b(s, store); @@ -129,27 +118,19 @@ namespace smt { var_data * d = m_var_data[v]; d->m_parent_stores.push_back(s); m_trail_stack.push(push_back_trail(d->m_parent_stores)); - 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_axiom2b(*it, s); - } + if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) + for (enode* n : d->m_parent_selects) + if (!m_params.m_array_cg || n->is_cgr()) + instantiate_axiom2b(n, s); } bool theory_array::instantiate_axiom2b_for(theory_var v) { bool result = false; var_data * d = m_var_data[v]; - ptr_vector::iterator it = d->m_parent_stores.begin(); - ptr_vector::iterator end = d->m_parent_stores.end(); - for (; it != end; ++it) { - ptr_vector::iterator it2 = d->m_parent_selects.begin(); - ptr_vector::iterator end2 = d->m_parent_selects.end(); - for (; it2 != end2; ++it2) - if (instantiate_axiom2b(*it2, *it)) + for (enode* n1 : d->m_parent_stores) + for (enode * n2 : d->m_parent_selects) + if (instantiate_axiom2b(n2, n1)) result = true; - } return result; } @@ -167,10 +148,8 @@ namespace smt { d->m_prop_upward = true; if (!m_params.m_array_delay_exp_axiom) instantiate_axiom2b_for(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); } } @@ -209,11 +188,9 @@ namespace smt { } d->m_stores.push_back(s); m_trail_stack.push(push_back_trail(d->m_stores)); - 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_axiom2a(*it, s); + for (enode * n : d->m_parent_selects) { + SASSERT(is_select(n)); + instantiate_axiom2a(n, s); } if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1) set_prop_upward(s); @@ -374,7 +351,7 @@ namespace smt { final_check_status theory_array::final_check_eh() { m_final_check_idx++; - final_check_status r; + final_check_status r = FC_DONE; if (m_params.m_array_lazy_ieq) { // Delay the creation of interface equalities... The // motivation is too give other theories and quantifier diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 21df02c76..2aaf2833f 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -210,17 +210,16 @@ namespace smt { - func_decl_ref_vector * theory_array_base::register_sort(sort * s_array) { unsigned dimension = get_dimension(s_array); func_decl_ref_vector * ext_skolems = 0; if (!m_sort2skolem.find(s_array, ext_skolems)) { + array_util util(get_manager()); ast_manager & m = get_manager(); ext_skolems = alloc(func_decl_ref_vector, m); for (unsigned i = 0; i < dimension; ++i) { sort * ext_sk_domain[2] = { s_array, s_array }; - parameter p(i); - func_decl * ext_sk_decl = m.mk_func_decl(get_id(), OP_ARRAY_EXT, 1, &p, 2, ext_sk_domain); + func_decl * ext_sk_decl = util.mk_array_ext(s_array, i); ext_skolems->push_back(ext_sk_decl); } m_sort2skolem.insert(s_array, ext_skolems); diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index 9b67e7011..b92092739 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -117,7 +117,7 @@ func_decl_ref bvarray2uf_rewriter_cfg::mk_uf_for_array(expr * e) { if (is_uninterp_const(e)) { if (m_emc) m_emc->insert(to_app(e)->get_decl(), - m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->insert(bv_f); @@ -193,7 +193,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr if (is_uninterp_const(e)) { if (m_emc) m_emc->insert(e->get_decl(), - m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + m_array_util.mk_as_array(bv_f)); } else if (m_fmc) m_fmc->insert(bv_f); @@ -207,7 +207,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr q = m_manager.mk_forall(1, sorts, names, body); extra_assertions.push_back(q); - result = m_array_util.mk_as_array(f->get_range(), bv_f); + result = m_array_util.mk_as_array(bv_f); TRACE("bvarray2uf_rw", tout << "result: " << mk_ismt2_pp(result, m_manager) << ")" << std::endl;); res = BR_DONE; @@ -234,7 +234,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr if (is_bv_array(t)) { // From [1]: For every array term t we create a fresh uninterpreted function f_t. f_t = mk_uf_for_array(t); - result = m_array_util.mk_as_array(m_manager.get_sort(t), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; } else if (has_bv_arrays) { @@ -274,7 +274,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr expr * v = args[0]; func_decl_ref f_t(mk_uf_for_array(t), m_manager); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; // Add \forall x . f_t(x) = v @@ -321,7 +321,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr expr_ref frllx(m_manager.mk_forall(1, sorts, names, body), m_manager); extra_assertions.push_back(frllx); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; } else if (m_array_util.is_store(f)) { @@ -342,7 +342,7 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr func_decl_ref f_s(mk_uf_for_array(s), m_manager); func_decl_ref f_t(mk_uf_for_array(t), m_manager); - result = m_array_util.mk_as_array(f->get_range(), f_t); + result = m_array_util.mk_as_array(f_t); res = BR_DONE; sort * sorts[1] = { get_index_sort(f->get_range()) }; From d2e27f6f1f33cf6e0ae05cb78976a35fd6423f5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 19 Oct 2017 11:25:44 -0700 Subject: [PATCH 06/57] remove redundant and wrong range type, in extension to changes made for #1223 Signed-off-by: Nikolaj Bjorner --- src/ast/array_decl_plugin.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 1257ab2c6..911bb3f27 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -191,8 +191,7 @@ public: app * mk_as_array(func_decl * f) { parameter param(f); - sort * s = f->get_range(); - return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, s); + return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, ¶m, 0, 0, 0); } }; From b2191cab020718362d544bad6e7624cf30948c97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 21 Oct 2017 18:46:35 -0400 Subject: [PATCH 07/57] disable eager clear of check-sat-result to fix #1318 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 9615e86ce..77dce80c8 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -774,7 +774,6 @@ bool cmd_context::is_func_decl(symbol const & s) const { } void cmd_context::insert(symbol const & s, func_decl * f) { - m_check_sat_result = 0; if (!m_check_logic(f)) { throw cmd_exception(m_check_logic.get_last_error()); } @@ -805,7 +804,6 @@ void cmd_context::insert(symbol const & s, func_decl * f) { } void cmd_context::insert(symbol const & s, psort_decl * p) { - m_check_sat_result = 0; if (m_psort_decls.contains(s)) { throw cmd_exception("sort already defined ", s); } @@ -819,7 +817,6 @@ void cmd_context::insert(symbol const & s, psort_decl * p) { void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) { expr_ref _t(t, m()); - m_check_sat_result = 0; if (m_builtin_decls.contains(s)) { throw cmd_exception("invalid macro/named expression, builtin symbol ", s); } From 42fbe19814cdb25d450b4e222252a6ded6361fa0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 21 Oct 2017 18:56:36 -0400 Subject: [PATCH 08/57] fix #1316, segmentation fault when numeric value is not internalized Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 44ce804e7..d55484384 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3466,6 +3466,8 @@ static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v) bool theory_seq::get_num_value(expr* e, rational& val) const { context& ctx = get_context(); expr_ref _val(m); + if (!ctx.e_internalized(e)) + return false; enode* next = ctx.get_enode(e), *n = next; do { if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) { From 77bbae65f5d602e1cf3cec81fb27720cd89a4370 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Oct 2017 08:17:38 -0700 Subject: [PATCH 09/57] fix #1319, fix #1320 Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 3 ++- src/muz/fp/dl_cmds.cpp | 3 ++- src/parsers/smt2/smt2parser.cpp | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 97a2c841a..6c0537936 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -453,7 +453,8 @@ namespace datalog { return new_pred; } - void context::add_rule(expr* rl, symbol const& name, unsigned bound) { + void context::add_rule(expr* rl, symbol const& name, unsigned bound) { + SASSERT(rl); m_rule_fmls.push_back(rl); m_rule_names.push_back(name); m_rule_bounds.push_back(bound); diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 42c614912..2610f821c 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -189,11 +189,12 @@ public: m_bound = bound; m_arg_idx++; } - virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); } + virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; } virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; } virtual void finalize(cmd_context & ctx) { } virtual void execute(cmd_context & ctx) { + if (!m_t) throw cmd_exception("invalid rule, expected formula"); m_dl_ctx->add_rule(m_t, m_name, m_bound); } }; diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index b43ee9f6e..fd592f7c7 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1881,6 +1881,8 @@ namespace smt2 { // the resultant expression is on the top of the stack TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";); expr_ref r(m()); + if (expr_stack().empty()) + throw parser_exception("invalid let expression"); r = expr_stack().back(); expr_stack().pop_back(); // remove local declarations from the stack From f63439603d3704f26b1d8e6030a7088840d0c314 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Oct 2017 21:16:46 -0700 Subject: [PATCH 10/57] streamlining proof generation (initial step of removing ast-manager dependency). Detect error in model creation when declaring constant with non-zero arity. See #1223 Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 2 + src/api/api_interp.cpp | 2 +- src/api/api_model.cpp | 9 +- src/ast/ast.cpp | 90 ++++++++---------- src/ast/ast.h | 8 +- src/ast/normal_forms/pull_quant.cpp | 4 +- src/ast/pattern/pattern_inference.cpp | 6 +- src/ast/scoped_proof.h | 2 +- src/cmd_context/context_params.cpp | 2 +- src/cmd_context/interpolant_cmds.cpp | 2 +- src/muz/base/dl_context.cpp | 2 +- src/muz/base/dl_rule.cpp | 4 +- src/muz/pdr/pdr_context.cpp | 2 +- src/muz/pdr/pdr_farkas_learner.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_itp_solver.h | 4 +- src/muz/spacer/spacer_util.cpp | 131 ++++++++++++-------------- src/parsers/smt/smtlib_solver.cpp | 2 +- src/smt/smt_conflict_resolution.cpp | 4 +- src/smt/smt_justification.cpp | 2 +- 20 files changed, 129 insertions(+), 153 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 6327ad40f..fa27c7887 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2843,6 +2843,8 @@ void fpa_example() { /*@}*/ /*@}*/ + + int main() { #ifdef LOG_Z3_CALLS Z3_open_log("z3.log"); diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp index fb2699e0a..416c71adf 100644 --- a/src/api/api_interp.cpp +++ b/src/api/api_interp.cpp @@ -249,7 +249,7 @@ extern "C" { params_ref _p; _p.set_bool("proof", true); // this is currently useless - scoped_proof_mode spm(mk_c(c)->m(), PGM_FINE); + scoped_proof_mode spm(mk_c(c)->m(), PGM_ENABLED); scoped_ptr sf = mk_smt_solver_factory(); scoped_ptr m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null)); m_solver.get()->updt_params(_p); // why do we have to do this? diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 540f014c6..bda33f186 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -255,8 +255,13 @@ extern "C" { LOG_Z3_add_const_interp(c, m, f, a); RESET_ERROR_CODE(); func_decl* d = to_func_decl(f); - model* mdl = to_model_ref(m); - mdl->register_decl(d, to_expr(a)); + if (d->get_arity() != 0) { + SET_ERROR_CODE(Z3_INVALID_ARG); + } + else { + model* mdl = to_model_ref(m); + mdl->register_decl(d, to_expr(a)); + } Z3_CATCH; } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9116c5d95..f903dc623 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2626,7 +2626,7 @@ bool ast_manager::is_fully_interp(sort * s) const { // ----------------------------------- proof * ast_manager::mk_proof(family_id fid, decl_kind k, unsigned num_args, expr * const * args) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(fid, k, num_args, args); } @@ -2662,8 +2662,7 @@ proof * ast_manager::mk_goal(expr * f) { } proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!p1 || !p2) return nullptr; SASSERT(has_fact(p1)); SASSERT(has_fact(p2)); CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))), @@ -2684,13 +2683,13 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { } proof * ast_manager::mk_reflexivity(expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_eq(e, e)); } proof * ast_manager::mk_oeq_reflexivity(expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_oeq(e, e)); } @@ -2705,8 +2704,7 @@ proof * ast_manager::mk_commutativity(app * f) { \brief Given a proof of p, return a proof of (p <=> true) */ proof * ast_manager::mk_iff_true(proof * pr) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!pr) return pr; SASSERT(has_fact(pr)); SASSERT(is_bool(get_fact(pr))); return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true())); @@ -2716,8 +2714,7 @@ proof * ast_manager::mk_iff_true(proof * pr) { \brief Given a proof of (not p), return a proof of (p <=> false) */ proof * ast_manager::mk_iff_false(proof * pr) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!pr) return pr; SASSERT(has_fact(pr)); SASSERT(is_not(get_fact(pr))); expr * p = to_app(get_fact(pr))->get_arg(0); @@ -2725,10 +2722,7 @@ proof * ast_manager::mk_iff_false(proof * pr) { } proof * ast_manager::mk_symmetry(proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (!p) - return p; + if (!p) return p; if (is_reflexivity(p)) return p; if (is_symmetry(p)) @@ -2741,8 +2735,6 @@ proof * ast_manager::mk_symmetry(proof * p) { } proof * ast_manager::mk_transitivity(proof * p1, proof * p2) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; if (!p1) return p2; if (!p2) @@ -2787,7 +2779,7 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2, proof * p3, proof * } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(num_proofs > 0); proof * r = proofs[0]; @@ -2797,9 +2789,9 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; - if (fine_grain_proofs()) + if (proofs_enabled()) return mk_transitivity(num_proofs, proofs); SASSERT(num_proofs > 0); if (num_proofs == 1) @@ -2817,7 +2809,7 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(f1->get_num_args() == f2->get_num_args()); SASSERT(f1->get_decl() == f2->get_decl()); @@ -2828,7 +2820,7 @@ proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned } proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); @@ -2837,7 +2829,7 @@ proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proo } proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); @@ -2846,7 +2838,7 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, } proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; if (!p) { return 0; @@ -2858,7 +2850,7 @@ proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) } proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); @@ -2867,25 +2859,25 @@ proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof } proof * ast_manager::mk_distributivity(expr * s, expr * r) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DISTRIBUTIVITY, mk_eq(s, r)); } proof * ast_manager::mk_rewrite(expr * s, expr * t) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); } proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); } proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -2894,37 +2886,37 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr } proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); } proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); } proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); } proof * ast_manager::mk_der(quantifier * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); } proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; vector params; for (unsigned i = 0; i < num_bind; ++i) { @@ -2959,7 +2951,7 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const { } proof * ast_manager::mk_def_axiom(expr * ax) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); } @@ -3001,7 +2993,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro new_lits.push_back(lit); } DEBUG_CODE({ - for (unsigned i = 1; m_proof_mode == PGM_FINE && i < num_proofs; i++) { + for (unsigned i = 1; proofs_enabled() && i < num_proofs; i++) { CTRACE("mk_unit_resolution_bug", !found.get(i, false), for (unsigned j = 0; j < num_proofs; j++) { if (j == i) tout << "Index " << i << " was not found:\n"; @@ -3080,14 +3072,11 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro } proof * ast_manager::mk_hypothesis(expr * h) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; return mk_app(m_basic_family_id, PR_HYPOTHESIS, h); } proof * ast_manager::mk_lemma(proof * p, expr * lemma) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; + if (!p) return p; SASSERT(has_fact(p)); CTRACE("mk_lemma", !is_false(get_fact(p)), tout << mk_ll_pp(p, *this) << "\n";); SASSERT(is_false(get_fact(p))); @@ -3100,7 +3089,7 @@ proof * ast_manager::mk_def_intro(expr * new_def) { } proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3109,10 +3098,7 @@ proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, pr } proof * ast_manager::mk_iff_oeq(proof * p) { - if (m_proof_mode == PGM_DISABLED) - return m_undef_proof; - if (!p) - return p; + if (!p) return p; SASSERT(has_fact(p)); SASSERT(is_iff(get_fact(p)) || is_oeq(get_fact(p))); @@ -3136,7 +3122,7 @@ bool ast_manager::check_nnf_proof_parents(unsigned num_proofs, proof * const * p } proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; @@ -3146,7 +3132,7 @@ proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * } proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; @@ -3156,7 +3142,7 @@ proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * } proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3165,7 +3151,7 @@ proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof } proof * ast_manager::mk_skolemization(expr * q, expr * e) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(is_bool(q)); SASSERT(is_bool(e)); @@ -3173,7 +3159,7 @@ proof * ast_manager::mk_skolemization(expr * q, expr * e) { } proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3182,7 +3168,7 @@ proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof } proof * ast_manager::mk_and_elim(proof * p, unsigned i) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(has_fact(p)); SASSERT(is_and(get_fact(p))); @@ -3193,7 +3179,7 @@ proof * ast_manager::mk_and_elim(proof * p, unsigned i) { } proof * ast_manager::mk_not_or_elim(proof * p, unsigned i) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; SASSERT(has_fact(p)); SASSERT(is_not(get_fact(p))); @@ -3216,7 +3202,7 @@ proof * ast_manager::mk_th_lemma( unsigned num_params, parameter const* params ) { - if (m_proof_mode == PGM_DISABLED) + if (proofs_disabled()) return m_undef_proof; ptr_buffer args; diff --git a/src/ast/ast.h b/src/ast/ast.h index 7e1645753..2d06d03de 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1396,8 +1396,7 @@ public: enum proof_gen_mode { PGM_DISABLED, - PGM_COARSE, - PGM_FINE + PGM_ENABLED }; // ----------------------------------- @@ -2088,15 +2087,14 @@ protected: proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2); proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3); + proof * mk_undef_proof() const { return m_undef_proof; } + public: bool proofs_enabled() const { return m_proof_mode != PGM_DISABLED; } bool proofs_disabled() const { return m_proof_mode == PGM_DISABLED; } - bool coarse_grain_proofs() const { return m_proof_mode == PGM_COARSE; } - bool fine_grain_proofs() const { return m_proof_mode == PGM_FINE; } proof_gen_mode proof_mode() const { return m_proof_mode; } void toggle_proof_mode(proof_gen_mode m) { m_proof_mode = m; } // APIs for creating proof objects return [undef] - proof * mk_undef_proof() const { return m_undef_proof; } bool is_proof(expr const * n) const { return is_app(n) && to_app(n)->get_decl()->get_range() == m_proof_sort; } diff --git a/src/ast/normal_forms/pull_quant.cpp b/src/ast/normal_forms/pull_quant.cpp index 239fd9008..ee618c747 100644 --- a/src/ast/normal_forms/pull_quant.cpp +++ b/src/ast/normal_forms/pull_quant.cpp @@ -229,7 +229,7 @@ struct pull_quant::imp { proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg))); } pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r)); @@ -240,7 +240,7 @@ struct pull_quant::imp { expr_ref new_expr(m_manager); pull_quant1(to_quantifier(n)->get_expr(), new_expr); pull_quant1(to_quantifier(n), new_expr, r); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); proof * p1 = 0; if (n != q1) { diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index 6a91dd85e..17d8747f2 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -606,7 +606,7 @@ bool pattern_inference_cfg::reduce_quantifier( result = m.update_quantifier_weight(tmp, new_weight); TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";); } - if (m.fine_grain_proofs()) + if (m.proofs_enabled()) result_pr = m.mk_rewrite(q, new_q); return true; } @@ -671,7 +671,7 @@ bool pattern_inference_cfg::reduce_quantifier( quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m); if (weight != q->get_weight()) new_q = m.update_quantifier_weight(new_q, weight); - if (m.fine_grain_proofs()) { + if (m.proofs_enabled()) { proof* new_body_pr = m.mk_reflexivity(new_body); result_pr = m.mk_quant_intro(q, new_q, new_body_pr); } @@ -689,7 +689,7 @@ bool pattern_inference_cfg::reduce_quantifier( warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); } new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr()); - if (m.fine_grain_proofs()) { + 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()))); } TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";); diff --git a/src/ast/scoped_proof.h b/src/ast/scoped_proof.h index 0a650ceb7..b2b3d7173 100644 --- a/src/ast/scoped_proof.h +++ b/src/ast/scoped_proof.h @@ -37,7 +37,7 @@ public: class scoped_proof : public scoped_proof_mode { public: - scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_FINE) {} + scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_ENABLED) {} }; class scoped_no_proof : public scoped_proof_mode { diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index 9a3339b84..f8646d41c 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -192,7 +192,7 @@ void context_params::get_solver_params(ast_manager const & m, params_ref & p, bo ast_manager * context_params::mk_ast_manager() { ast_manager * r = alloc(ast_manager, - m_proof ? PGM_FINE : PGM_DISABLED, + m_proof ? PGM_ENABLED : PGM_DISABLED, m_trace ? m_trace_file_name.c_str() : 0); if (m_smtlib2_compliant) r->enable_int_real_coercions(false); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp index b5bbea18c..8b9f0ebd8 100644 --- a/src/cmd_context/interpolant_cmds.cpp +++ b/src/cmd_context/interpolant_cmds.cpp @@ -147,7 +147,7 @@ static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, par ast_manager &_m = ctx.m(); // TODO: the following is a HACK to enable proofs in the old smt solver // When we stop using that solver, this hack can be removed - scoped_proof_mode spm(_m,PGM_FINE); + scoped_proof_mode spm(_m,PGM_ENABLED); ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); p.set_bool("proof", true); scoped_ptr sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic()); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 6c0537936..39e044ec3 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -462,7 +462,7 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); - scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _scp(m, generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); while (m_rule_fmls_head < m_rule_fmls.size()) { expr* fml = m_rule_fmls[m_rule_fmls_head].get(); proof* p = generate_proof_trace()?m.mk_asserted(fml):0; diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 367795c9b..4f832c4c9 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -141,7 +141,7 @@ namespace datalog { void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { - scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); proof_ref pr(p, m); expr_ref fml1(m); bind_variables(fml, true, fml1); @@ -343,7 +343,7 @@ namespace datalog { } TRACE("dl", tout << rule_expr << "\n";); - scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED); proof_ref pr(m); if (m_ctx.generate_proof_trace()) { pr = m.mk_asserted(rule_expr); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index fd734ea66..e6d91c87e 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1825,7 +1825,7 @@ namespace pdr { m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); } if (!classify.is_bool()) { - m.toggle_proof_mode(PGM_FINE); + m.toggle_proof_mode(PGM_ENABLED); m_fparams.m_arith_bound_prop = BP_NONE; m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 29037f180..4f47cb554 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -372,7 +372,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), - m_pr(PGM_FINE), + m_pr(PGM_ENABLED), m_constr(0), m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index f549205c3..7ab78d453 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2139,7 +2139,7 @@ void context::reset_lemma_generalizers() void context::init_lemma_generalizers(datalog::rule_set& rules) { reset_lemma_generalizers(); - m.toggle_proof_mode(PGM_FINE); + m.toggle_proof_mode(PGM_ENABLED); smt_params &fparams = m_pm.fparams (); if (!m_params.spacer_eq_prop ()) { fparams.m_arith_bound_prop = BP_NONE; diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index fce2c4a9c..cab19c8ef 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -135,7 +135,7 @@ public: virtual expr * get_assumption(unsigned idx) const {return m_solver.get_assumption(idx);} virtual std::ostream &display(std::ostream &out) const - {m_solver.display(out); return out;} + { return m_solver.display(out); } /* check_sat_result interface */ @@ -170,7 +170,7 @@ public: public: scoped_bg(itp_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} ~scoped_bg() - {if(m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} + {if (m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} }; }; } diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index a277c9ed6..31190a97f 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -72,73 +72,67 @@ namespace spacer { // model_evaluator_util::model_evaluator_util(ast_manager& m) : - m(m), m_mev(NULL) - { reset (NULL); } + m(m), m_mev(nullptr) { + reset (nullptr); + } model_evaluator_util::~model_evaluator_util() {reset (NULL);} -void model_evaluator_util::reset(model* model) -{ + void model_evaluator_util::reset(model* model) { if (m_mev) { dealloc(m_mev); m_mev = NULL; } m_model = model; - if (!m_model) { return; } + if (!m_model) { return; } m_mev = alloc(model_evaluator, *m_model); } - -bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) -{ + + bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) { m_mev->set_model_completion (model_completion); try { m_mev->operator() (e, result); return true; - } catch (model_evaluator_exception &ex) { + } + catch (model_evaluator_exception &ex) { (void)ex; TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); return false; } } - + bool model_evaluator_util::eval(const expr_ref_vector &v, - expr_ref& res, bool model_completion) -{ + expr_ref& res, bool model_completion) { expr_ref e(m); e = mk_and (v); return eval(e, res, model_completion); } - - -bool model_evaluator_util::is_true(const expr_ref_vector &v) -{ + + + bool model_evaluator_util::is_true(const expr_ref_vector &v) { expr_ref res(m); return eval (v, res, false) && m.is_true (res); } - -bool model_evaluator_util::is_false(expr *x) -{ + + bool model_evaluator_util::is_false(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_false (res); } -bool model_evaluator_util::is_true(expr *x) -{ + + bool model_evaluator_util::is_true(expr *x) { expr_ref res(m); return eval(x, res, false) && m.is_true (res); } - - -void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) -{ + + void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); flatten_and(fml, conjs); obj_map diseqs; expr* n, *lhs, *rhs; for (unsigned i = 0; i < conjs.size(); ++i) { - if (m.is_not(conjs[i].get(), n) && - m.is_eq(n, lhs, rhs)) { + if (m.is_not(conjs[i].get(), n) && m.is_eq(n, lhs, rhs)) { if (!m.is_value(rhs)) { std::swap(lhs, rhs); } @@ -157,12 +151,12 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) pr = m.mk_asserted(m.mk_true()); obj_map::iterator it = diseqs.begin(); obj_map::iterator end = diseqs.end(); - for (; it != end; ++it) { - if (it->m_value >= threshold) { - model.eval(it->m_key, val); - sub.insert(it->m_key, val, pr); - conjs.push_back(m.mk_eq(it->m_key, val)); - num_deleted += it->m_value; + for (auto const& kv : diseqs) { + if (kv.m_value >= threshold) { + model.eval(kv.m_key, val); + sub.insert(kv.m_key, val, pr); + conjs.push_back(m.mk_eq(kv.m_key, val)); + num_deleted += kv.m_value; } } if (orig_size < conjs.size()) { @@ -178,14 +172,17 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) SASSERT(orig_size <= 1 + conjs.size()); if (i + 1 == orig_size) { // no-op. - } else if (orig_size <= conjs.size()) { + } + else if (orig_size <= conjs.size()) { // no-op - } else { + } + else { SASSERT(orig_size == 1 + conjs.size()); --orig_size; --i; } - } else { + } + else { conjs[i] = tmp; } } @@ -202,9 +199,8 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) ast_manager& m; public: ite_hoister(ast_manager& m): m(m) {} - - br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) - { + + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { if (m.is_ite(f)) { return BR_FAILED; } @@ -233,13 +229,12 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) struct ite_hoister_cfg: public default_rewriter_cfg { ite_hoister m_r; bool rewrite_patterns() const { return false; } - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) - { + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { return m_r.mk_app_core(f, num, args, result); } ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} }; - + class ite_hoister_star : public rewriter_tpl { ite_hoister_cfg m_cfg; public: @@ -247,9 +242,8 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) rewriter_tpl(m, false, m_cfg), m_cfg(m, p) {} }; - -void hoist_non_bool_if(expr_ref& fml) -{ + + void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); scoped_no_proof _sp(m); params_ref p; @@ -266,8 +260,7 @@ void hoist_non_bool_if(expr_ref& fml) bool m_is_dl; bool m_test_for_utvpi; - bool is_numeric(expr* e) const - { + bool is_numeric(expr* e) const { if (a.is_numeral(e)) { return true; } @@ -278,13 +271,11 @@ void hoist_non_bool_if(expr_ref& fml) return false; } - bool is_arith_expr(expr *e) const - { + bool is_arith_expr(expr *e) const { return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); } - - bool is_offset(expr* e) const - { + + bool is_offset(expr* e) const { if (a.is_numeral(e)) { return true; } @@ -315,47 +306,44 @@ void hoist_non_bool_if(expr_ref& fml) return !is_arith_expr(e); } - bool is_minus_one(expr const * e) const - { - rational r; - return a.is_numeral(e, r) && r.is_minus_one(); + bool is_minus_one(expr const * e) const { + rational r; + return a.is_numeral(e, r) && r.is_minus_one(); } - bool test_ineq(expr* e) const - { + bool test_ineq(expr* e) const { SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e)); SASSERT(to_app(e)->get_num_args() == 2); expr * lhs = to_app(e)->get_arg(0); expr * rhs = to_app(e)->get_arg(1); if (is_offset(lhs) && is_offset(rhs)) - { return true; } + { return true; } if (!is_numeric(rhs)) - { std::swap(lhs, rhs); } + { std::swap(lhs, rhs); } if (!is_numeric(rhs)) - { return false; } + { return false; } // lhs can be 'x' or '(+ x (* -1 y))' if (is_offset(lhs)) - { return true; } + { return true; } expr* arg1, *arg2; if (!a.is_add(lhs, arg1, arg2)) - { return false; } + { return false; } // x if (m_test_for_utvpi) { return is_offset(arg1) && is_offset(arg2); } if (is_arith_expr(arg1)) - { std::swap(arg1, arg2); } + { std::swap(arg1, arg2); } if (is_arith_expr(arg1)) - { return false; } + { return false; } // arg2: (* -1 y) expr* m1, *m2; if (!a.is_mul(arg2, m1, m2)) - { return false; } + { return false; } return is_minus_one(m1) && is_offset(m2); } - bool test_eq(expr* e) const - { + bool test_eq(expr* e) const { expr* lhs, *rhs; VERIFY(m.is_eq(e, lhs, rhs)); if (!a.is_int_real(lhs)) { @@ -370,9 +358,8 @@ void hoist_non_bool_if(expr_ref& fml) !a.is_mul(lhs) && !a.is_mul(rhs); } - - bool test_term(expr* e) const - { + + bool test_term(expr* e) const { if (m.is_bool(e)) { return true; } @@ -490,7 +477,7 @@ bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) * eliminate simple equalities using qe_lite * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays */ - void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, +void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, const model_ref& M, bool reduce_all_selects, bool use_native_mbp, bool dont_sub) { diff --git a/src/parsers/smt/smtlib_solver.cpp b/src/parsers/smt/smtlib_solver.cpp index b4487cbc5..339be2ddd 100644 --- a/src/parsers/smt/smtlib_solver.cpp +++ b/src/parsers/smt/smtlib_solver.cpp @@ -34,7 +34,7 @@ Revision History: namespace smtlib { solver::solver(): - m_ast_manager(m_params.m_proof ? PGM_FINE : PGM_DISABLED, + m_ast_manager(m_params.m_proof ? PGM_ENABLED : PGM_DISABLED, m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0), m_ctx(0), m_error_code(0) { diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index cb1465d94..80168df18 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -810,8 +810,6 @@ namespace smt { m_new_proofs.push_back(pr); return pr; } - if (m_manager.coarse_grain_proofs()) - return pr; TRACE("norm_eq_proof", tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n"; tout << mk_ll_pp(pr, m_manager, true, false);); @@ -1217,7 +1215,7 @@ namespace smt { mk_proof(rhs, c, prs2); while (!prs2.empty()) { proof * pr = prs2.back(); - if (m_manager.fine_grain_proofs()) { + if (m_manager.proofs_enabled()) { pr = m_manager.mk_symmetry(pr); m_new_proofs.push_back(pr); prs1.push_back(pr); diff --git a/src/smt/smt_justification.cpp b/src/smt/smt_justification.cpp index c8de45644..440da7297 100644 --- a/src/smt/smt_justification.cpp +++ b/src/smt/smt_justification.cpp @@ -129,7 +129,7 @@ namespace smt { if (m_node1 != m_node1->get_root()) { proof * pr = cr.get_proof(m_node1, m_node1->get_root()); - if (pr && m.fine_grain_proofs()) + if (pr && m.proofs_enabled()) pr = m.mk_symmetry(pr); prs.push_back(pr); if (!pr) From 7f254710aadad615589ffe55537f24c100a23ef9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 23 Oct 2017 21:38:10 -0700 Subject: [PATCH 11/57] patch build failure Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f903dc623..040ca4078 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2683,14 +2683,10 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { } proof * ast_manager::mk_reflexivity(expr * e) { - if (proofs_disabled()) - return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_eq(e, e)); } proof * ast_manager::mk_oeq_reflexivity(expr * e) { - if (proofs_disabled()) - return m_undef_proof; return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_oeq(e, e)); } @@ -2705,6 +2701,8 @@ proof * ast_manager::mk_commutativity(app * f) { */ proof * ast_manager::mk_iff_true(proof * pr) { if (!pr) return pr; + if (proofs_disabled()) + return m_undef_proof; SASSERT(has_fact(pr)); SASSERT(is_bool(get_fact(pr))); return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true())); @@ -2779,8 +2777,6 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2, proof * p3, proof * } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return m_undef_proof; SASSERT(num_proofs > 0); proof * r = proofs[0]; for (unsigned i = 1; i < num_proofs; i++) @@ -2789,11 +2785,8 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { - if (proofs_disabled()) - return m_undef_proof; - if (proofs_enabled()) - return mk_transitivity(num_proofs, proofs); - SASSERT(num_proofs > 0); + if (num_proofs == 0) + return nullptr; if (num_proofs == 1) return proofs[0]; DEBUG_CODE({ @@ -2809,8 +2802,6 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs } proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return m_undef_proof; SASSERT(f1->get_num_args() == f2->get_num_args()); SASSERT(f1->get_decl() == f2->get_decl()); ptr_buffer args; @@ -2820,8 +2811,6 @@ proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned } proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; @@ -2829,8 +2818,6 @@ proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proo } proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { - if (proofs_disabled()) - return m_undef_proof; SASSERT(get_sort(f1) == get_sort(f2)); sort * s = get_sort(f1); sort * d[2] = { s, s }; @@ -2838,11 +2825,7 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, } proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (proofs_disabled()) - return m_undef_proof; - if (!p) { - return 0; - } + if (!p) return nullptr; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); SASSERT(is_iff(get_fact(p))); @@ -2850,8 +2833,7 @@ proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) } proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof * p) { - if (proofs_disabled()) - return m_undef_proof; + if (!p) return nullptr; SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(has_fact(p)); SASSERT(is_oeq(get_fact(p))); @@ -2859,8 +2841,6 @@ proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof } proof * ast_manager::mk_distributivity(expr * s, expr * r) { - if (proofs_disabled()) - return m_undef_proof; return mk_app(m_basic_family_id, PR_DISTRIBUTIVITY, mk_eq(s, r)); } From d630838b38f6956aa418c81036c7b60d7d0e4163 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 24 Oct 2017 09:39:16 +0200 Subject: [PATCH 12/57] add a basic printer into graphviz (http://graphviz.org/) for proofs - proofs are output into file `proof.dot` if `(get-proof-graph)` is in the input - use `dot -Txlib proof.dot` to see the proof - use `dot -Tsvg proof.dot` to get a svg file --- src/ast/CMakeLists.txt | 1 + src/ast/ast_pp_dot.cpp | 126 +++++++++++++++++++++++++++++++++ src/ast/ast_pp_dot.h | 24 +++++++ src/cmd_context/basic_cmds.cpp | 21 ++++++ 4 files changed, 172 insertions(+) create mode 100644 src/ast/ast_pp_dot.cpp create mode 100644 src/ast/ast_pp_dot.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 0a14d9473..4dcdd2a35 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -10,6 +10,7 @@ z3_add_component(ast ast_printer.cpp ast_smt2_pp.cpp ast_smt_pp.cpp + ast_pp_dot.cpp ast_translation.cpp ast_util.cpp bv_decl_plugin.cpp diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp new file mode 100644 index 000000000..8e3406ccb --- /dev/null +++ b/src/ast/ast_pp_dot.cpp @@ -0,0 +1,126 @@ +/*++ + +Abstract: Pretty-printer for proofs in Graphviz format + +--*/ + +#include "util/util.h" +#include "util/map.h" +#include "ast_pp_dot.h" + +// string escaping for DOT +std::string escape_dot(std::string const & s) { + std::string res; + for (auto c : s) { + if (c == '\n') + res.append("\\l"); + else + res.push_back(c); + } + return res; +} + +// map from proofs to unique IDs +typedef map, default_eq > expr2id; +typedef map, default_eq > set_expr; + +// temporary structure for traversing the proof and printing it +struct ast_pp_dot_st { + const ast_pp_dot * m_pp; + set_expr m_printed; + expr2id m_id_map; + svector m_to_print; + std::ostream & m_out; + unsigned m_next_id; + + ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) : + m_pp(pp), + m_out(out), + m_next_id(0), + m_id_map(), + m_to_print(), + m_printed() {} + + void push_term(const expr * a) { m_to_print.push_back(a); } + + void pp_loop() { + // DFS traversal + auto& m = get_manager(); + while (!m_to_print.empty()) { + const expr * a = m_to_print.back(); + m_to_print.pop_back(); + if (!m_printed.contains(a)) { + m_printed.insert(a, true); + if (m.is_proof(a)) + pp_step(to_app(a)); + else + pp_atomic_step(a); + } + } + } + +private: + + ast_manager & get_manager() const { return m_pp->get_manager(); } + + // label for an expression + std::string label_of_expr(const expr * e) const { + expr_ref er((expr*)e, get_manager()); + std::ostringstream out; + out << er << std::flush; + return escape_dot(out.str()); + } + + void pp_atomic_step(const expr * e) { + unsigned id = get_id(e); + m_out << "node_" << id << " [shape=box,label=\"" << label_of_expr(e) << "\"] ;" << std::endl; + } + + void pp_step(const proof * p) { + auto m = get_manager(); + unsigned num_args = p->get_num_args(); + TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << num_args); + if (num_args > 0) { + // print result + expr* p_res = p->get_args()[num_args-1]; // result + unsigned id = get_id(p); + m_out << "node_" << id << " [shape=box,label=\"" << label_of_expr(p_res) << "\"]" << std::endl; + // now print edges to parents (except last one, which is the result) + std::string label = p->get_decl()->get_name().str(); + for (unsigned i = 0 ; i+1 < num_args; ++i) { + expr* parent = p->get_args()[i]; + // explore parent, also print a link to it + push_term(to_app(parent)); + m_out << "node_" << id << " -> " << "node_" << get_id((expr*)parent) + << "[label=\"" << label << "\"];" << std::endl;; + } + } else { + pp_atomic_step(p); + } + } + + // find a unique ID for this proof + unsigned get_id(const expr * e) { + if (m_id_map.contains(e)) { + return m_id_map[e]; + } else { + auto id = m_next_id ++; + m_id_map.insert(e, id); + return id; + } + } + +}; + +// main printer +std::ostream & ast_pp_dot::pp(std::ostream & out) const { + out << "digraph proof { " << std::endl; + ast_pp_dot_st pp_st(this, out); + pp_st.push_term(m_pr); + pp_st.pp_loop(); + out << std::endl << " } " << std::endl << std::flush; + return out; +} + +std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p) { return p.pp(out); } + diff --git a/src/ast/ast_pp_dot.h b/src/ast/ast_pp_dot.h new file mode 100644 index 000000000..38c45e00b --- /dev/null +++ b/src/ast/ast_pp_dot.h @@ -0,0 +1,24 @@ +/*++ + +Abstract: Pretty-printer for proofs in Graphviz format + +--*/ + +#pragma once + +#include +#include "ast_pp.h" + +class ast_pp_dot { + ast_manager & m_manager; + proof * const m_pr; + + public: + ast_pp_dot(proof *pr, ast_manager &m) : m_manager(m), m_pr(pr) {} + ast_pp_dot(proof_ref &e) : m_manager(e.m()), m_pr(e.get()) {} + + std::ostream & pp(std::ostream & out) const; + ast_manager & get_manager() const { return m_manager; } +}; + +std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p); \ No newline at end of file diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 21b66febd..60dd09f59 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -20,6 +20,7 @@ Notes: #include "util/version.h" #include "ast/ast_smt_pp.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_pp_dot.h" #include "ast/ast_pp.h" #include "ast/array_decl_plugin.h" #include "ast/pp.h" @@ -202,6 +203,25 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", { } }); +ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it in graphviz", { + if (!ctx.produce_proofs()) + throw cmd_exception("proof construction is not enabled, use command (set-option :produce-proofs true)"); + if (!ctx.has_manager() || + ctx.cs_state() != cmd_context::css_unsat) + throw cmd_exception("proof is not available"); + proof_ref pr(ctx.m()); + pr = ctx.get_check_sat_result()->get_proof(); + if (pr == 0) + throw cmd_exception("proof is not available"); + if (ctx.well_sorted_check_enabled() && !is_well_sorted(ctx.m(), pr)) { + throw cmd_exception("proof is not well sorted"); + } + + // TODO: specify file into which the proof should be printed + std::ofstream out("proof.dot"); + out << ast_pp_dot(pr) << std::endl; +}); + static void print_core(cmd_context& ctx) { ptr_vector core; ctx.get_check_sat_result()->get_unsat_core(core); @@ -840,6 +860,7 @@ void install_basic_cmds(cmd_context & ctx) { ctx.insert(alloc(get_assignment_cmd)); ctx.insert(alloc(get_assertions_cmd)); ctx.insert(alloc(get_proof_cmd)); + ctx.insert(alloc(get_proof_graph_cmd)); ctx.insert(alloc(get_unsat_core_cmd)); ctx.insert(alloc(set_option_cmd)); ctx.insert(alloc(get_option_cmd)); From 24edb8fb47db0c680438c9473212160c93aac2db Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 24 Oct 2017 09:51:47 +0200 Subject: [PATCH 13/57] add some colors to the proof output --- src/ast/ast_pp_dot.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index 8e3406ccb..feffa71f1 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -32,6 +32,7 @@ struct ast_pp_dot_st { svector m_to_print; std::ostream & m_out; unsigned m_next_id; + bool m_first; ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) : m_pp(pp), @@ -39,7 +40,8 @@ struct ast_pp_dot_st { m_next_id(0), m_id_map(), m_to_print(), - m_printed() {} + m_printed(), + m_first(true) {} void push_term(const expr * a) { m_to_print.push_back(a); } @@ -73,7 +75,7 @@ private: void pp_atomic_step(const expr * e) { unsigned id = get_id(e); - m_out << "node_" << id << " [shape=box,label=\"" << label_of_expr(e) << "\"] ;" << std::endl; + m_out << "node_" << id << " [shape=box,color=\"yellow\",style=\"filled\",label=\"" << label_of_expr(e) << "\"] ;" << std::endl; } void pp_step(const proof * p) { @@ -84,7 +86,11 @@ private: // print result expr* p_res = p->get_args()[num_args-1]; // result unsigned id = get_id(p); - m_out << "node_" << id << " [shape=box,label=\"" << label_of_expr(p_res) << "\"]" << std::endl; + const char* color = + m_first ? (m_first=false,"color=\"red\"") : num_args==1 ? "color=\"yellow\"": ""; + m_out << "node_" << id << + " [shape=box,style=\"filled\",label=\"" << label_of_expr(p_res) << "\"" + << color << "]" << std::endl; // now print edges to parents (except last one, which is the result) std::string label = p->get_decl()->get_name().str(); for (unsigned i = 0 ; i+1 < num_args; ++i) { From ed526b808d402e5b66bfcb8962ae58568993d00b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 24 Oct 2017 10:16:22 +0200 Subject: [PATCH 14/57] add parameter to specify the file into which dot proofs are to be printed --- src/cmd_context/basic_cmds.cpp | 5 +++-- src/cmd_context/context_params.cpp | 5 +++++ src/cmd_context/context_params.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 60dd09f59..65c8860b1 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -217,8 +217,9 @@ ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it throw cmd_exception("proof is not well sorted"); } - // TODO: specify file into which the proof should be printed - std::ofstream out("proof.dot"); + context_params& params = ctx.params(); + const std::string& file = params.m_dot_proof_file; + std::ofstream out(file); out << ast_pp_dot(pr) << std::endl; }); diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index f8646d41c..78f4223fc 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -111,6 +111,9 @@ void context_params::set(char const * param, char const * value) { else if (p == "trace_file_name") { m_trace_file_name = value; } + else if (p == "dot_proof_file") { + m_dot_proof_file = value; + } else if (p == "unsat_core") { set_bool(m_unsat_core, param, value); } @@ -146,6 +149,7 @@ void context_params::updt_params(params_ref const & p) { 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"); + m_dot_proof_file = p.get_str("dot_proof_file", "proof.dot"); m_unsat_core = p.get_bool("unsat_core", m_unsat_core); m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count); m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant); @@ -161,6 +165,7 @@ void context_params::collect_param_descrs(param_descrs & d) { 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"); + d.insert("dot_proof_file", CPK_STRING, "file in which to output graphical proofs", "proof.dot"); d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false"); d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false"); collect_solver_param_descrs(d); diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index c238af556..df62057fe 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -30,6 +30,7 @@ class context_params { public: bool m_auto_config; bool m_proof; + std::string m_dot_proof_file; bool m_interpolants; bool m_debug_ref_count; bool m_trace; From 72c9134424c973f8fae47d40806bbf8a3d43bfda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 02:26:39 -0700 Subject: [PATCH 15/57] fixing regressions introduced when reducing astm proof dependencies Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 13 ++++++++++--- src/smt/asserted_formulas.cpp | 4 ++-- src/test/proof_checker.cpp | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 040ca4078..3dbd0bc69 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -805,7 +805,6 @@ func_decl * basic_decl_plugin::mk_proof_decl(char const* name, basic_op_kind k, } func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_parents) { - SASSERT(k == PR_UNDEF || m_manager->proofs_enabled()); switch (static_cast(k)) { // // A description of the semantics of the proof @@ -2701,8 +2700,6 @@ proof * ast_manager::mk_commutativity(app * f) { */ proof * ast_manager::mk_iff_true(proof * pr) { if (!pr) return pr; - if (proofs_disabled()) - return m_undef_proof; SASSERT(has_fact(pr)); SASSERT(is_bool(get_fact(pr))); return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true())); @@ -2845,18 +2842,21 @@ proof * ast_manager::mk_distributivity(expr * s, expr * r) { } proof * ast_manager::mk_rewrite(expr * s, expr * t) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); } proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); } proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; ptr_buffer args; @@ -2866,36 +2866,42 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr } proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); } proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); } proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); } proof * ast_manager::mk_der(quantifier * q, expr * e) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); } proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; vector params; @@ -2931,6 +2937,7 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const { } proof * ast_manager::mk_def_axiom(expr * ax) { + SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 1ed5f2fe1..9f68f2412 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -101,14 +101,14 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vectorget_num_args(); ++i) { expr* arg = to_app(e)->get_arg(i); - proof_ref _pr(m.mk_and_elim(pr, i), m); + proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : 0, m); push_assertion(arg, _pr, result); } } else if (m.is_not(e, e1) && m.is_or(e1)) { for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { expr* arg = to_app(e1)->get_arg(i); - proof_ref _pr(m.mk_not_or_elim(pr, i), m); + proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : 0, m); expr_ref narg(mk_not(m, arg), m); push_assertion(narg, _pr, result); } diff --git a/src/test/proof_checker.cpp b/src/test/proof_checker.cpp index adf77e12e..33a908f24 100644 --- a/src/test/proof_checker.cpp +++ b/src/test/proof_checker.cpp @@ -8,7 +8,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_ll_pp.h" void tst_checker1() { - ast_manager m(PGM_FINE); + ast_manager m(PGM_ENABLED); expr_ref a(m); proof_ref p1(m), p2(m), p3(m), p4(m); expr_ref_vector side_conditions(m); From 607eba1720da71154f3bccf9bea20e677939327c Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 24 Oct 2017 11:44:28 +0200 Subject: [PATCH 16/57] account for review --- src/ast/ast_pp_dot.cpp | 42 ++++++++++++++++++++++-------------------- src/ast/ast_pp_dot.h | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index feffa71f1..eb4ec80fe 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -11,6 +11,7 @@ Abstract: Pretty-printer for proofs in Graphviz format // string escaping for DOT std::string escape_dot(std::string const & s) { std::string res; + res.reserve(s.size()); // preallocate for (auto c : s) { if (c == '\n') res.append("\\l"); @@ -21,8 +22,8 @@ std::string escape_dot(std::string const & s) { } // map from proofs to unique IDs -typedef map, default_eq > expr2id; -typedef map, default_eq > set_expr; +typedef obj_map expr2id; +typedef obj_map set_expr; // temporary structure for traversing the proof and printing it struct ast_pp_dot_st { @@ -33,6 +34,7 @@ struct ast_pp_dot_st { std::ostream & m_out; unsigned m_next_id; bool m_first; + ast_manager & m_manager; ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) : m_pp(pp), @@ -41,19 +43,21 @@ struct ast_pp_dot_st { m_id_map(), m_to_print(), m_printed(), - m_first(true) {} + m_first(true), + m_manager(pp->get_manager()) {} + + ~ast_pp_dot_st() = default; void push_term(const expr * a) { m_to_print.push_back(a); } void pp_loop() { // DFS traversal - auto& m = get_manager(); while (!m_to_print.empty()) { const expr * a = m_to_print.back(); m_to_print.pop_back(); if (!m_printed.contains(a)) { m_printed.insert(a, true); - if (m.is_proof(a)) + if (m().is_proof(a)) pp_step(to_app(a)); else pp_atomic_step(a); @@ -63,11 +67,11 @@ struct ast_pp_dot_st { private: - ast_manager & get_manager() const { return m_pp->get_manager(); } + inline ast_manager & m() const { return m_manager; } // label for an expression std::string label_of_expr(const expr * e) const { - expr_ref er((expr*)e, get_manager()); + expr_ref er((expr*)e, m()); std::ostringstream out; out << er << std::flush; return escape_dot(out.str()); @@ -79,22 +83,21 @@ private: } void pp_step(const proof * p) { - auto m = get_manager(); - unsigned num_args = p->get_num_args(); TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << num_args); - if (num_args > 0) { + if (m().has_fact(p)) { // print result - expr* p_res = p->get_args()[num_args-1]; // result + expr* p_res = m().get_fact(p); // result of proof step unsigned id = get_id(p); + unsigned num_parents = m().get_num_parents(p); const char* color = - m_first ? (m_first=false,"color=\"red\"") : num_args==1 ? "color=\"yellow\"": ""; + m_first ? (m_first=false,"color=\"red\"") : num_parents==0 ? "color=\"yellow\"": ""; m_out << "node_" << id << " [shape=box,style=\"filled\",label=\"" << label_of_expr(p_res) << "\"" << color << "]" << std::endl; // now print edges to parents (except last one, which is the result) std::string label = p->get_decl()->get_name().str(); - for (unsigned i = 0 ; i+1 < num_args; ++i) { - expr* parent = p->get_args()[i]; + for (unsigned i = 0 ; i < num_parents; ++i) { + expr* parent = m().get_parent(p, i); // explore parent, also print a link to it push_term(to_app(parent)); m_out << "node_" << id << " -> " << "node_" << get_id((expr*)parent) @@ -107,13 +110,12 @@ private: // find a unique ID for this proof unsigned get_id(const expr * e) { - if (m_id_map.contains(e)) { - return m_id_map[e]; - } else { - auto id = m_next_id ++; - m_id_map.insert(e, id); - return id; + unsigned id = 0; + if (!m_id_map.find(e, id)) { + id = m_next_id++; + m_id_map.insert(e, id); } + return id; } }; diff --git a/src/ast/ast_pp_dot.h b/src/ast/ast_pp_dot.h index 38c45e00b..537754e83 100644 --- a/src/ast/ast_pp_dot.h +++ b/src/ast/ast_pp_dot.h @@ -16,7 +16,7 @@ class ast_pp_dot { public: ast_pp_dot(proof *pr, ast_manager &m) : m_manager(m), m_pr(pr) {} ast_pp_dot(proof_ref &e) : m_manager(e.m()), m_pr(e.get()) {} - + std::ostream & pp(std::ostream & out) const; ast_manager & get_manager() const { return m_manager; } }; From d67f3c14668b8f6f679f361575ad6cd3461dfa6f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 03:08:56 -0700 Subject: [PATCH 17/57] create proofs folder, move proof-post-order utility to proofs directory, fix regression with proofs Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 4 +- src/CMakeLists.txt | 2 +- .../{proof_checker => proofs}/CMakeLists.txt | 5 ++- .../proof_checker.cpp | 3 +- .../{proof_checker => proofs}/proof_checker.h | 0 .../proofs/proof_utils.cpp} | 37 ++++++++++--------- .../proofs/proof_utils.h} | 21 +++++------ src/muz/pdr/pdr_context.cpp | 2 +- src/muz/spacer/CMakeLists.txt | 1 - src/muz/spacer/spacer_context.cpp | 2 +- src/muz/spacer/spacer_legacy_frames.cpp | 2 +- src/muz/spacer/spacer_unsat_core_learner.cpp | 6 +-- src/muz/spacer/spacer_unsat_core_learner.h | 2 +- src/muz/spacer/spacer_unsat_core_plugin.cpp | 2 +- src/muz/spacer/spacer_virtual_solver.cpp | 2 +- src/smt/CMakeLists.txt | 2 +- src/smt/asserted_formulas.cpp | 10 ++--- src/smt/smt_context.cpp | 2 +- src/test/proof_checker.cpp | 2 +- 19 files changed, 53 insertions(+), 54 deletions(-) rename src/ast/{proof_checker => proofs}/CMakeLists.txt (60%) rename src/ast/{proof_checker => proofs}/proof_checker.cpp (99%) rename src/ast/{proof_checker => proofs}/proof_checker.h (100%) rename src/{muz/spacer/spacer_proof_utils.cpp => ast/proofs/proof_utils.cpp} (93%) rename src/{muz/spacer/spacer_proof_utils.h => ast/proofs/proof_utils.h} (58%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 923b948a6..ddf439e10 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -43,14 +43,14 @@ def init_project_def(): add_lib('cmd_context', ['solver', 'rewriter', 'interp']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') - add_lib('proof_checker', ['rewriter'], 'ast/proof_checker') + add_lib('proofs', ['rewriter'], 'ast/proofs') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params') add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', - 'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa', 'lp']) + 'substitution', 'grobner', 'euclid', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp']) add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('smt_tactic', ['smt'], 'smt/tactic') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 277335ce9..cfe6e5265 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,7 +67,7 @@ add_subdirectory(interp) add_subdirectory(cmd_context) add_subdirectory(cmd_context/extra_cmds) add_subdirectory(parsers/smt2) -add_subdirectory(ast/proof_checker) +add_subdirectory(ast/proofs) add_subdirectory(ast/fpa) add_subdirectory(ast/macros) add_subdirectory(ast/pattern) diff --git a/src/ast/proof_checker/CMakeLists.txt b/src/ast/proofs/CMakeLists.txt similarity index 60% rename from src/ast/proof_checker/CMakeLists.txt rename to src/ast/proofs/CMakeLists.txt index 5c947adec..6eedb0fac 100644 --- a/src/ast/proof_checker/CMakeLists.txt +++ b/src/ast/proofs/CMakeLists.txt @@ -1,6 +1,7 @@ -z3_add_component(proof_checker +z3_add_component(proofs SOURCES proof_checker.cpp + proof_utils.cpp COMPONENT_DEPENDENCIES rewriter -) +) \ No newline at end of file diff --git a/src/ast/proof_checker/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp similarity index 99% rename from src/ast/proof_checker/proof_checker.cpp rename to src/ast/proofs/proof_checker.cpp index afe2baeed..3f9438229 100644 --- a/src/ast/proof_checker/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -4,10 +4,9 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" -// include "spc_decl_plugin.h" #include "ast/ast_smt_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" diff --git a/src/ast/proof_checker/proof_checker.h b/src/ast/proofs/proof_checker.h similarity index 100% rename from src/ast/proof_checker/proof_checker.h rename to src/ast/proofs/proof_checker.h diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/ast/proofs/proof_utils.cpp similarity index 93% rename from src/muz/spacer/spacer_proof_utils.cpp rename to src/ast/proofs/proof_utils.cpp index 6edb29881..bd82696ea 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -3,7 +3,7 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_proof_utils.cpp + proof_utils.cpp Abstract: Utilities to traverse and manipulate proofs @@ -16,24 +16,23 @@ Revision History: --*/ -#include "muz/spacer/spacer_proof_utils.h" #include "ast/ast_util.h" #include "ast/ast_pp.h" +#include "ast/proofs/proof_utils.h" +#include "ast/proofs/proof_checker.h" -#include "ast/proof_checker/proof_checker.h" -namespace spacer { -ProofIteratorPostOrder::ProofIteratorPostOrder(proof* root, ast_manager& manager) : m(manager) +proof_post_order::proof_post_order(proof* root, ast_manager& manager) : m(manager) {m_todo.push_back(root);} -bool ProofIteratorPostOrder::hasNext() +bool proof_post_order::hasNext() {return !m_todo.empty();} /* * iterative post-order depth-first search (DFS) through the proof DAG */ -proof* ProofIteratorPostOrder::next() +proof* proof_post_order::next() { while (!m_todo.empty()) { proof* currentNode = m_todo.back(); @@ -42,7 +41,8 @@ proof* ProofIteratorPostOrder::next() if (!m_visited.is_marked(currentNode)) { bool existsUnvisitedParent = false; - // add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result + // add unprocessed premises to stack for DFS. + // If there is at least one unprocessed premise, don't compute the result // for currentProof now, but wait until those unprocessed premises are processed. for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) { SASSERT(m.is_proof(currentNode->get_arg(i))); @@ -67,7 +67,7 @@ proof* ProofIteratorPostOrder::next() } } // we have already iterated through all inferences - return NULL; + return nullptr; } @@ -117,20 +117,21 @@ class reduce_hypotheses { return hyp_mark; } - void compute_marks(proof* pr) - { + void compute_marks(proof* pr) { proof *p; - ProofIteratorPostOrder pit(pr, m); + proof_post_order pit(pr, m); while (pit.hasNext()) { p = pit.next(); if (m.is_hypothesis(p)) { m_hypmark.mark(p, true); m_hyps.insert(m.get_fact(p)); - } else { + } + else { bool hyp_mark = compute_mark1(p); // collect units that are hyp-free and are used as hypotheses somewhere - if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) - { m_units.insert(m.get_fact(p), p); } + if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) { + m_units.insert(m.get_fact(p), p); + } } } } @@ -220,6 +221,7 @@ class reduce_hypotheses { return m_units.contains(e); } + proof *mk_lemma_core(proof *pf, expr *fact) { ptr_buffer args; @@ -319,8 +321,8 @@ public: reset(); } }; -void reduce_hypotheses(proof_ref &pr) -{ + +void reduce_hypotheses(proof_ref &pr) { ast_manager &m = pr.get_manager(); class reduce_hypotheses hypred(m); hypred(pr); @@ -329,4 +331,3 @@ void reduce_hypotheses(proof_ref &pr) SASSERT(pc.check(pr, side)); ); } -} diff --git a/src/muz/spacer/spacer_proof_utils.h b/src/ast/proofs/proof_utils.h similarity index 58% rename from src/muz/spacer/spacer_proof_utils.h rename to src/ast/proofs/proof_utils.h index f2897f7ec..7963d52de 100644 --- a/src/muz/spacer/spacer_proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -3,7 +3,7 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_proof_utils.cpp + proof_utils.h Abstract: Utilities to traverse and manipulate proofs @@ -16,28 +16,27 @@ Revision History: --*/ -#ifndef _SPACER_PROOF_UTILS_H_ -#define _SPACER_PROOF_UTILS_H_ +#ifndef _PROOF_UTILS_H_ +#define _PROOF_UTILS_H_ #include "ast/ast.h" -namespace spacer { /* * iterator, which traverses the proof in depth-first post-order. */ -class ProofIteratorPostOrder { + +class proof_post_order { public: - ProofIteratorPostOrder(proof* refutation, ast_manager& manager); + proof_post_order(proof* refutation, ast_manager& manager); bool hasNext(); proof* next(); private: ptr_vector m_todo; - ast_mark m_visited; // the proof nodes we have already visited - - ast_manager& m; + ast_mark m_visited; // the proof nodes we have already visited + ast_manager& m; }; - void reduce_hypotheses(proof_ref &pr); -} + + #endif diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index e6d91c87e..a1878dc7a 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -41,7 +41,7 @@ Notes: #include "ast/ast_smt2_pp.h" #include "qe/qe_lite.h" #include "ast/ast_ll_pp.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" #include "muz/base/proof_utils.h" #include "muz/base/dl_boogie_proof.h" diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index bc2f45b43..94e429171 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -15,7 +15,6 @@ z3_add_component(spacer spacer_itp_solver.cpp spacer_virtual_solver.cpp spacer_legacy_mbp.cpp - spacer_proof_utils.cpp spacer_unsat_core_learner.cpp spacer_unsat_core_plugin.cpp spacer_matrix.cpp diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 7ab78d453..b057730d8 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -40,7 +40,7 @@ Notes: #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" #include "ast/ast_util.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" #include "ast/scoped_proof.h" #include "muz/spacer/spacer_qe_project.h" diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index 9c302e5fd..dd2a16abd 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -23,7 +23,7 @@ #include "ast/ast_smt2_pp.h" #include "ast/ast_ll_pp.h" #include "ast/ast_util.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" #include "muz/base/proof_utils.h" #include "ast/scoped_proof.h" diff --git a/src/muz/spacer/spacer_unsat_core_learner.cpp b/src/muz/spacer/spacer_unsat_core_learner.cpp index 222ca146c..d478b1e8f 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.cpp +++ b/src/muz/spacer/spacer_unsat_core_learner.cpp @@ -41,7 +41,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e // transform proof in order to get a proof which is better suited for unsat-core-extraction proof_ref pr(root, m); - spacer::reduce_hypotheses(pr); + reduce_hypotheses(pr); STRACE("spacer.unsat_core_learner", verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; ); @@ -50,7 +50,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e collect_symbols_b(asserted_b); // traverse proof - ProofIteratorPostOrder it(root, m); + proof_post_order it(root, m); while (it.hasNext()) { proof* currentNode = it.next(); @@ -138,7 +138,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e std::unordered_map id_to_small_id; unsigned counter = 0; - ProofIteratorPostOrder it2(root, m); + proof_post_order it2(root, m); while (it2.hasNext()) { proof* currentNode = it2.next(); diff --git a/src/muz/spacer/spacer_unsat_core_learner.h b/src/muz/spacer/spacer_unsat_core_learner.h index 6ee7c3b37..a7c9f6aa7 100644 --- a/src/muz/spacer/spacer_unsat_core_learner.h +++ b/src/muz/spacer/spacer_unsat_core_learner.h @@ -20,7 +20,7 @@ Revision History: #include "ast/ast.h" #include "muz/spacer/spacer_util.h" -#include "muz/spacer/spacer_proof_utils.h" +#include "ast/proofs/proof_utils.h" namespace spacer { diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 0d90d2653..3f1e53778 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -20,13 +20,13 @@ Revision History: #include "ast/rewriter/bool_rewriter.h" #include "ast/arith_decl_plugin.h" +#include "ast/proofs/proof_utils.h" #include "solver/solver.h" #include "smt/smt_farkas_util.h" #include "smt/smt_solver.h" -#include "muz/spacer/spacer_proof_utils.h" #include "muz/spacer/spacer_matrix.h" #include "muz/spacer/spacer_unsat_core_plugin.h" #include "muz/spacer/spacer_unsat_core_learner.h" diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index ebaef14f0..244a97d22 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -23,7 +23,7 @@ Notes: #include "muz/spacer/spacer_util.h" #include "ast/rewriter/bool_rewriter.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "ast/scoped_proof.h" diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 41890dd05..e102bd28b 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -75,7 +75,7 @@ z3_add_component(smt normal_forms parser_util pattern - proof_checker + proofs proto_model simplex substitution diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 9f68f2412..dd92f250a 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -163,7 +163,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { } void asserted_formulas::assert_expr(expr * e) { - assert_expr(e, m.mk_asserted(e)); + assert_expr(e, m.proofs_enabled() ? m.mk_asserted(e) : nullptr); } void asserted_formulas::get_assertions(ptr_vector & result) const { @@ -365,7 +365,7 @@ void asserted_formulas::nnf_cnf() { CASSERT("well_sorted", is_well_sorted(m, n)); apply_nnf(n, push_todo, push_todo_prs, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); - pr = m.mk_modus_ponens(pr, pr1); + pr = m.proofs_enabled() ? m.mk_modus_ponens(pr, pr1) : nullptr; push_todo.push_back(r1); push_todo_prs.push_back(pr); @@ -506,16 +506,16 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } if (is_gt(rhs, lhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); - m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); + m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); return; } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } if (m.is_not(n, n1)) { - m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr)); + m_scoped_substitution.insert(n1, m.mk_false(), m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr); } else { - m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr)); + m_scoped_substitution.insert(n, m.mk_true(), m.proofs_enabled() ? m.mk_iff_true(pr) : nullptr); } } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 48d02da26..c508a65cb 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -23,7 +23,7 @@ Revision History: #include "ast/ast_ll_pp.h" #include "util/warning.h" #include "smt/smt_quick_checker.h" -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "ast/ast_util.h" #include "smt/uses_theory.h" #include "model/model.h" diff --git a/src/test/proof_checker.cpp b/src/test/proof_checker.cpp index 33a908f24..7a9b619cd 100644 --- a/src/test/proof_checker.cpp +++ b/src/test/proof_checker.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast/proof_checker/proof_checker.h" +#include "ast/proofs/proof_checker.h" #include "ast/ast_ll_pp.h" void tst_checker1() { From 70f7846af5e736032daed9c6becb50257a2c98c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 03:18:59 -0700 Subject: [PATCH 18/57] move spacer_marshal to under parsers/smt2 Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/CMakeLists.txt | 1 - src/parsers/smt2/CMakeLists.txt | 1 + .../smt2/marshal.cpp} | 22 +++++++------------ .../smt2/marshal.h} | 5 +---- 4 files changed, 10 insertions(+), 19 deletions(-) rename src/{muz/spacer/spacer_marshal.cpp => parsers/smt2/marshal.cpp} (71%) rename src/{muz/spacer/spacer_marshal.h => parsers/smt2/marshal.h} (91%) diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 94e429171..97c991e2a 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -7,7 +7,6 @@ z3_add_component(spacer spacer_farkas_learner.cpp spacer_generalizers.cpp spacer_manager.cpp - spacer_marshal.cpp spacer_prop_solver.cpp spacer_smt_context_manager.cpp spacer_sym_mux.cpp diff --git a/src/parsers/smt2/CMakeLists.txt b/src/parsers/smt2/CMakeLists.txt index 1467d95c6..022cce2f2 100644 --- a/src/parsers/smt2/CMakeLists.txt +++ b/src/parsers/smt2/CMakeLists.txt @@ -1,5 +1,6 @@ z3_add_component(smt2parser SOURCES + marshal.cpp smt2parser.cpp smt2scanner.cpp COMPONENT_DEPENDENCIES diff --git a/src/muz/spacer/spacer_marshal.cpp b/src/parsers/smt2/marshal.cpp similarity index 71% rename from src/muz/spacer/spacer_marshal.cpp rename to src/parsers/smt2/marshal.cpp index 68c90bd33..ae144e491 100644 --- a/src/muz/spacer/spacer_marshal.cpp +++ b/src/parsers/smt2/marshal.cpp @@ -2,14 +2,14 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_marshal.cpp + marshal.cpp Abstract: marshaling and unmarshaling of expressions --*/ -#include "muz/spacer/spacer_marshal.h" +#include "parsers/smt2/marshal.h" #include @@ -18,39 +18,33 @@ Abstract: #include "util/vector.h" #include "ast/ast_smt_pp.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" -namespace spacer { -std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m) -{ +std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m) { ast_smt_pp pp(m); pp.display_smt2(os, e); return os; } -std::string marshal(expr_ref e, ast_manager &m) -{ +std::string marshal(expr_ref e, ast_manager &m) { std::stringstream ss; marshal(ss, e, m); return ss.str(); } -expr_ref unmarshal(std::istream &is, ast_manager &m) -{ +expr_ref unmarshal(std::istream &is, ast_manager &m) { cmd_context ctx(false, &m); ctx.set_ignore_check(true); if (!parse_smt2_commands(ctx, is)) { return expr_ref(0, m); } ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); - if (it == end) { return expr_ref(m.mk_true(), m); } unsigned size = static_cast(end - it); - return expr_ref(m.mk_and(size, it), m); + return expr_ref(mk_and(m, size, it), m); } -expr_ref unmarshal(std::string s, ast_manager &m) -{ +expr_ref unmarshal(std::string s, ast_manager &m) { std::istringstream is(s); return unmarshal(is, m); } -} diff --git a/src/muz/spacer/spacer_marshal.h b/src/parsers/smt2/marshal.h similarity index 91% rename from src/muz/spacer/spacer_marshal.h rename to src/parsers/smt2/marshal.h index 95cb8f26a..ebc2c0426 100644 --- a/src/muz/spacer/spacer_marshal.h +++ b/src/parsers/smt2/marshal.h @@ -2,7 +2,7 @@ Copyright (c) 2017 Arie Gurfinkel Module Name: - spacer_marshal.h + marshal.h Abstract: @@ -17,14 +17,11 @@ Abstract: #include "ast/ast.h" -namespace spacer { std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m); std::string marshal(expr_ref e, ast_manager &m); expr_ref unmarshal(std::string s, ast_manager &m); expr_ref unmarshal(std::istream &is, ast_manager &m); -} - #endif From e6e1d94cf9d7a3fa2b5c60131c9e80a6e7c18384 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 03:39:00 -0700 Subject: [PATCH 19/57] fix build issues Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_dot.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index eb4ec80fe..df3de730f 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -6,7 +6,7 @@ Abstract: Pretty-printer for proofs in Graphviz format #include "util/util.h" #include "util/map.h" -#include "ast_pp_dot.h" +#include "ast/ast_pp_dot.h" // string escaping for DOT std::string escape_dot(std::string const & s) { @@ -23,28 +23,27 @@ std::string escape_dot(std::string const & s) { // map from proofs to unique IDs typedef obj_map expr2id; -typedef obj_map set_expr; // temporary structure for traversing the proof and printing it struct ast_pp_dot_st { - const ast_pp_dot * m_pp; - set_expr m_printed; - expr2id m_id_map; - svector m_to_print; - std::ostream & m_out; - unsigned m_next_id; - bool m_first; ast_manager & m_manager; + std::ostream & m_out; + const ast_pp_dot * m_pp; + unsigned m_next_id; + expr2id m_id_map; + obj_hashtable m_printed; + svector m_to_print; + bool m_first; ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) : - m_pp(pp), + m_manager(pp->get_manager()), m_out(out), + m_pp(pp), m_next_id(0), m_id_map(), m_to_print(), m_printed(), - m_first(true), - m_manager(pp->get_manager()) {} + m_first(true) {} ~ast_pp_dot_st() = default; @@ -56,7 +55,7 @@ struct ast_pp_dot_st { const expr * a = m_to_print.back(); m_to_print.pop_back(); if (!m_printed.contains(a)) { - m_printed.insert(a, true); + m_printed.insert(a); if (m().is_proof(a)) pp_step(to_app(a)); else @@ -83,7 +82,7 @@ private: } void pp_step(const proof * p) { - TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << num_args); + TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << p->get_num_args() << "\n";); if (m().has_fact(p)) { // print result expr* p_res = m().get_fact(p); // result of proof step From eda3c6258b07ee9707081498557dc9ba56cb3358 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 24 Oct 2017 12:53:24 +0100 Subject: [PATCH 20/57] backward comp --- src/ast/ast_pp_dot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index df3de730f..ebbf4b2b2 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -45,7 +45,7 @@ struct ast_pp_dot_st { m_printed(), m_first(true) {} - ~ast_pp_dot_st() = default; + ~ast_pp_dot_st() {}; void push_term(const expr * a) { m_to_print.push_back(a); } From 637a0fa1393dd6e7c99cf0bda15b0824a3fecb7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 08:49:25 -0700 Subject: [PATCH 21/57] unused warnings Signed-off-by: Nikolaj Bjorner --- src/ast/ast_pp_dot.cpp | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 2 -- src/muz/spacer/spacer_util.cpp | 2 -- src/muz/spacer/spacer_virtual_solver.cpp | 4 ++++ src/muz/spacer/spacer_virtual_solver.h | 3 ++- src/smt/theory_array_base.cpp | 1 - src/tactic/core/dom_simplify_tactic.cpp | 2 +- src/tactic/core/dom_simplify_tactic.h | 4 +--- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/ast/ast_pp_dot.cpp b/src/ast/ast_pp_dot.cpp index df3de730f..e3782cb21 100644 --- a/src/ast/ast_pp_dot.cpp +++ b/src/ast/ast_pp_dot.cpp @@ -41,8 +41,8 @@ struct ast_pp_dot_st { m_pp(pp), m_next_id(0), m_id_map(), - m_to_print(), m_printed(), + m_to_print(), m_first(true) {} ~ast_pp_dot_st() = default; diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 13a7599a9..220295dad 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3076,8 +3076,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * split_fp(x, sgn, e, s); mk_is_nan(x, x_is_nan); - sort * fp_srt = m.get_sort(x); - expr_ref unspec(m); mk_to_ieee_bv_unspecified(f, num, args, unspec); diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 31190a97f..83042cd6d 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -149,8 +149,6 @@ namespace spacer { expr_ref val(m), tmp(m); proof_ref pr(m); pr = m.mk_asserted(m.mk_true()); - obj_map::iterator it = diseqs.begin(); - obj_map::iterator end = diseqs.end(); for (auto const& kv : diseqs) { if (kv.m_value >= threshold) { model.eval(kv.m_key, val); diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 244a97d22..87a21336c 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -81,6 +81,8 @@ static bool matches_fact(expr_ref_vector &args, expr* &match) } +// TBD: move to ast/proofs/elim_aux_assertions + class elim_aux_assertions { app_ref m_aux; public: @@ -404,6 +406,7 @@ void virtual_solver::refresh() m_head = 0; } +#ifdef NOT_USED_ANYWHERE void virtual_solver::reset() { SASSERT(!m_pushed); @@ -411,6 +414,7 @@ void virtual_solver::reset() m_assertions.reset(); m_factory.refresh(); } +#endif void virtual_solver::get_labels(svector &r) { diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 14e05302e..3ccd89ef5 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -91,8 +91,9 @@ public: virtual void set_produce_models(bool f); virtual bool get_produce_models(); virtual smt_params &fparams(); +#ifdef NOT_USED_ANYWHERE virtual void reset(); - +#endif virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index 2aaf2833f..472053fdc 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -218,7 +218,6 @@ namespace smt { ast_manager & m = get_manager(); ext_skolems = alloc(func_decl_ref_vector, m); for (unsigned i = 0; i < dimension; ++i) { - sort * ext_sk_domain[2] = { s_array, s_array }; func_decl * ext_sk_decl = util.mk_array_ext(s_array, i); ext_skolems->push_back(ext_sk_decl); } diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index ee94c5e57..2099eebf0 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -441,7 +441,7 @@ ptr_vector const & dom_simplify_tactic::tree(expr * e) { } -// ---------------------- +// --------------------- // expr_substitution_simplifier bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 6cd94a3c1..56eea8d9a 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -95,7 +95,6 @@ class dom_simplify_tactic : public tactic { expr_ref_vector m_trail, m_args; obj_map m_result; expr_dominators m_dominators; - unsigned m_scope_level; unsigned m_depth; unsigned m_max_depth; ptr_vector m_empty; @@ -128,8 +127,7 @@ public: dom_simplify_tactic(ast_manager & m, dom_simplifier* s, params_ref const & p = params_ref()): m(m), m_simplifier(s), m_params(p), m_trail(m), m_args(m), - m_dominators(m), - m_scope_level(0), m_depth(0), m_max_depth(1024), m_forward(true) {} + m_dominators(m), m_depth(0), m_max_depth(1024), m_forward(true) {} virtual ~dom_simplify_tactic(); From 1315c8d7dea433574d28bd0e22f782ff784c68fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 09:03:28 -0700 Subject: [PATCH 22/57] rename repeated class apart Signed-off-by: Nikolaj Bjorner --- src/muz/base/proof_utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz/base/proof_utils.cpp b/src/muz/base/proof_utils.cpp index 3b2d50fdc..87355a07b 100644 --- a/src/muz/base/proof_utils.cpp +++ b/src/muz/base/proof_utils.cpp @@ -9,7 +9,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_smt2_pp.h" #include "ast/rewriter/var_subst.h" -class reduce_hypotheses { +class reduce_hypotheses0 { typedef obj_hashtable expr_set; ast_manager& m; // reference for any expression created by the tranformation @@ -137,7 +137,7 @@ class reduce_hypotheses { } public: - reduce_hypotheses(ast_manager& m): m(m), m_refs(m) {} + reduce_hypotheses0(ast_manager& m): m(m), m_refs(m) {} void operator()(proof_ref& pr) { proof_ref tmp(m); @@ -416,7 +416,7 @@ public: void proof_utils::reduce_hypotheses(proof_ref& pr) { ast_manager& m = pr.get_manager(); - class reduce_hypotheses reduce(m); + class reduce_hypotheses0 reduce(m); reduce(pr); CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";); } From f27ac24fa075279df553687d17154d391a69b1fd Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 24 Oct 2017 17:27:58 +0100 Subject: [PATCH 23/57] Add example of using Z3's new model construction C API. This API was requested in #1223. This example uses the new `Z3_mk_model()`, `Z3_add_const_interp()` , `Z3_add_func_interp()`, and `Z3_mk_as_array()` API calls. --- examples/c/test_capi.c | 171 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index fa27c7887..433c7ebcf 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2840,6 +2840,176 @@ void fpa_example() { Z3_del_context(ctx); } +/** + \brief Demonstrates some basic features of model construction +*/ + +void mk_model_example() { + printf("\nmk_model_example\n"); + LOG_MSG("mk_model_example"); + Z3_context ctx = mk_context(); + // Construct empty model + Z3_model m = Z3_mk_model(ctx); + Z3_model_inc_ref(ctx, m); + + // Create constants "a" and "b" + Z3_sort intSort = Z3_mk_int_sort(ctx); + Z3_symbol aSymbol = Z3_mk_string_symbol(ctx, "a"); + Z3_func_decl aFuncDecl = Z3_mk_func_decl(ctx, aSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + Z3_ast aApp = Z3_mk_app(ctx, aFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + Z3_symbol bSymbol = Z3_mk_string_symbol(ctx, "b"); + Z3_func_decl bFuncDecl = Z3_mk_func_decl(ctx, bSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + Z3_ast bApp = Z3_mk_app(ctx, bFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + + // Create array "c" that maps int to int. + Z3_symbol cSymbol = Z3_mk_string_symbol(ctx, "c"); + Z3_sort int2intArraySort = Z3_mk_array_sort(ctx, + /*domain=*/intSort, + /*range=*/intSort); + Z3_func_decl cFuncDecl = Z3_mk_func_decl(ctx, cSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/int2intArraySort); + Z3_ast cApp = Z3_mk_app(ctx, cFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + + // Create numerals to be used in model + Z3_ast zeroNumeral = Z3_mk_int(ctx, 0, intSort); + Z3_ast oneNumeral = Z3_mk_int(ctx, 1, intSort); + Z3_ast twoNumeral = Z3_mk_int(ctx, 2, intSort); + Z3_ast threeNumeral = Z3_mk_int(ctx, 3, intSort); + Z3_ast fourNumeral = Z3_mk_int(ctx, 4, intSort); + + // Add assignments to model + // a == 1 + Z3_add_const_interp(ctx, m, aFuncDecl, oneNumeral); + // b == 2 + Z3_add_const_interp(ctx, m, bFuncDecl, twoNumeral); + + // Create a fresh function that represents + // reading from array. + Z3_sort arrayDomain[] = {intSort}; + Z3_func_decl cAsFuncDecl = Z3_mk_fresh_func_decl(ctx, + /*prefix=*/"", + /*domain_size*/ 1, + /*domain=*/arrayDomain, + /*sort=*/intSort); + // Create function interpretation with default + // value of "0". + Z3_func_interp cAsFuncInterp = + Z3_add_func_interp(ctx, m, cAsFuncDecl, + /*default_value=*/zeroNumeral); + Z3_func_interp_inc_ref(ctx, cAsFuncInterp); + // Add [0] = 3 + Z3_ast_vector zeroArgs = Z3_mk_ast_vector(ctx); + Z3_ast_vector_inc_ref(ctx, zeroArgs); + Z3_ast_vector_push(ctx, zeroArgs, zeroNumeral); + Z3_func_interp_add_entry(ctx, cAsFuncInterp, zeroArgs, threeNumeral); + // Add [1] = 4 + Z3_ast_vector oneArgs = Z3_mk_ast_vector(ctx); + Z3_ast_vector_inc_ref(ctx, oneArgs); + Z3_ast_vector_push(ctx, oneArgs, oneNumeral); + Z3_func_interp_add_entry(ctx, cAsFuncInterp, oneArgs, fourNumeral); + + // Now use the `(_ as_array)` to associate + // the `cAsFuncInterp` with the `cFuncDecl` + // in the model + Z3_ast cFuncDeclAsArray = Z3_mk_as_array(ctx, cAsFuncDecl); + Z3_add_const_interp(ctx, m, cFuncDecl, cFuncDeclAsArray); + + // Print the model + Z3_string modelAsString = Z3_model_to_string(ctx, m); + printf("Model:\n%s\n", modelAsString); + + // Check the interpretations we expect to be present + // are. + Z3_func_decl expectedInterpretations[] = {aFuncDecl, bFuncDecl, cFuncDecl}; + for (int index = 0; + index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl); + ++index) { + Z3_func_decl d = expectedInterpretations[index]; + if (Z3_model_has_interp(ctx, m, d)) { + printf("Found interpretation for \"%s\"\n", + Z3_ast_to_string(ctx, Z3_func_decl_to_ast(ctx, d))); + } else { + printf("Missing interpretation"); + exit(1); + } + } + + // Evaluate a + b under model + Z3_ast addArgs[] = {aApp, bApp}; + Z3_ast aPlusB = Z3_mk_add(ctx, + /*num_args=*/2, + /*args=*/addArgs); + Z3_ast aPlusBEval = NULL; + Z3_bool aPlusBEvalSuccess = + Z3_model_eval(ctx, m, aPlusB, + /*model_completion=*/Z3_FALSE, &aPlusBEval); + if (aPlusBEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + int aPlusBValue = 0; + Z3_bool getAPlusBValueSuccess = + Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); + if (getAPlusBValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for a+b\n"); + exit(1); + } + printf("Evaluated a + b = %d\n", aPlusBValue); + if (aPlusBValue != 3) { + printf("a+b did not evaluate to expected value\n"); + exit(1); + } + + // Evaluate c[0] + c[1] + c[2] under model + Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral); + Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral); + Z3_ast c2 = Z3_mk_select(ctx, cApp, twoNumeral); + Z3_ast arrayAddArgs[] = {c0, c1, c2}; + Z3_ast arrayAdd = Z3_mk_add(ctx, + /*num_args=*/3, + /*args=*/arrayAddArgs); + Z3_ast arrayAddEval = NULL; + Z3_bool arrayAddEvalSuccess = + Z3_model_eval(ctx, m, arrayAdd, + /*model_completion=*/Z3_FALSE, &arrayAddEval); + if (arrayAddEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + int arrayAddValue = 0; + Z3_bool getArrayAddValueSuccess = + Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); + if (getArrayAddValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); + exit(1); + } + printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); + if (arrayAddValue != 7) { + printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); + exit(1); + } + + Z3_ast_vector_dec_ref(ctx, oneArgs); + Z3_ast_vector_dec_ref(ctx, zeroArgs); + Z3_func_interp_dec_ref(ctx, cAsFuncInterp); + Z3_model_dec_ref(ctx, m); + Z3_del_context(ctx); +} + /*@}*/ /*@}*/ @@ -2888,5 +3058,6 @@ int main() { substitute_example(); substitute_vars_example(); fpa_example(); + mk_model_example(); return 0; } From fc822af707ebe1c80708587d524a838849743464 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 09:59:55 -0700 Subject: [PATCH 24/57] move proof utils under ast Signed-off-by: Nikolaj Bjorner --- src/ast/proofs/proof_utils.cpp | 676 ++++++++++++++++++++++ src/ast/proofs/proof_utils.h | 31 +- src/muz/base/CMakeLists.txt | 1 - src/muz/base/dl_boogie_proof.cpp | 2 +- src/muz/base/dl_util.h | 128 +---- src/muz/base/proof_utils.cpp | 680 ----------------------- src/muz/base/proof_utils.h | 48 -- src/muz/pdr/pdr_context.cpp | 1 - src/muz/pdr/pdr_farkas_learner.cpp | 8 +- src/muz/pdr/pdr_generalizers.cpp | 6 +- src/muz/spacer/spacer_farkas_learner.cpp | 8 +- src/muz/spacer/spacer_legacy_frames.cpp | 2 +- 12 files changed, 722 insertions(+), 869 deletions(-) delete mode 100644 src/muz/base/proof_utils.cpp delete mode 100644 src/muz/base/proof_utils.h diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp index bd82696ea..b6c8b58d7 100644 --- a/src/ast/proofs/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -20,6 +20,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/proofs/proof_utils.h" #include "ast/proofs/proof_checker.h" +#include "util/container_util.h" @@ -331,3 +332,678 @@ void reduce_hypotheses(proof_ref &pr) { SASSERT(pc.check(pr, side)); ); } + + + +#include "ast/ast_smt2_pp.h" +#include "ast/rewriter/var_subst.h" + +class reduce_hypotheses0 { + typedef obj_hashtable expr_set; + ast_manager& m; + // reference for any expression created by the tranformation + expr_ref_vector m_refs; + // currently computed result + obj_map m_cache; + // map conclusions to closed proofs that derive them + obj_map m_units; + // currently active units + ptr_vector m_units_trail; + // size of m_units_trail at the last push + unsigned_vector m_limits; + // map from proofs to active hypotheses + obj_map m_hypmap; + // refernce train for hypotheses sets + ptr_vector m_hyprefs; + ptr_vector m_literals; + + void reset() { + m_refs.reset(); + m_cache.reset(); + m_units.reset(); + m_units_trail.reset(); + m_limits.reset(); + std::for_each(m_hyprefs.begin(), m_hyprefs.end(), delete_proc()); + m_hypmap.reset(); + m_hyprefs.reset(); + m_literals.reset(); + } + + void push() { + m_limits.push_back(m_units_trail.size()); + } + + void pop() { + unsigned sz = m_limits.back(); + while (m_units_trail.size() > sz) { + m_units.remove(m_units_trail.back()); + m_units_trail.pop_back(); + } + m_limits.pop_back(); + } + + void get_literals(expr* clause) { + m_literals.reset(); + if (m.is_or(clause)) { + m_literals.append(to_app(clause)->get_num_args(), to_app(clause)->get_args()); + } + else { + m_literals.push_back(clause); + } + } + + void add_hypotheses(proof* p) { + expr_set* hyps = 0; + bool inherited = false; + if (p->get_decl_kind() == PR_HYPOTHESIS) { + hyps = alloc(expr_set); + hyps->insert(m.get_fact(p)); + m_hyprefs.push_back(hyps); + } + else { + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + expr_set* hyps1 = m_hypmap.find(m.get_parent(p, i)); + if (hyps1) { + if (!hyps) { + hyps = hyps1; + inherited = true; + continue; + } + if (inherited) { + hyps = alloc(expr_set,*hyps); + m_hyprefs.push_back(hyps); + inherited = false; + } + set_union(*hyps, *hyps1); + } + } + } + m_hypmap.insert(p, hyps); + } + + expr_ref complement_lit(expr* e) { + expr* e1; + if (m.is_not(e, e1)) { + return expr_ref(e1, m); + } + else { + return expr_ref(m.mk_not(e), m); + } + } + + bool in_hypotheses(expr* e, expr_set* hyps) { + if (!hyps) { + return false; + } + expr_ref not_e = complement_lit(e); + return hyps->contains(not_e); + } + + bool contains_hypothesis(proof* p) { + ptr_vector todo; + ast_mark visit; + todo.push_back(p); + while (!todo.empty()) { + p = todo.back(); + todo.pop_back(); + if (visit.is_marked(p)) { + continue; + } + visit.mark(p, true); + if (PR_HYPOTHESIS == p->get_decl_kind()) { + return true; + } + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + todo.push_back(m.get_parent(p, i)); + } + } + return false; + } + + bool is_closed(proof* p) { + expr_set* hyps = m_hypmap.find(p); + return !hyps || hyps->empty(); + } + +public: + reduce_hypotheses0(ast_manager& m): m(m), m_refs(m) {} + + void operator()(proof_ref& pr) { + proof_ref tmp(m); + tmp = pr; + elim(pr); + reset(); + CTRACE("proof_utils", contains_hypothesis(pr), + tout << "Contains hypothesis:\n"; + tout << mk_ismt2_pp(tmp, m) << "\n====>\n"; + tout << mk_ismt2_pp(pr, m) << "\n";); + + } + + void elim(proof_ref& p) { + proof_ref tmp(m); + proof* result = p.get(); + if (m_cache.find(p, result)) { + p = result; + return; + } + //SASSERT (p.get () == result); + switch(p->get_decl_kind()) { + case PR_HYPOTHESIS: + // replace result by m_units[m.get_fact (p)] if defined + // AG: This is the main step. Replace a hypothesis by a derivation of its consequence + if (!m_units.find(m.get_fact(p), result)) { + // restore ther result back to p + result = p.get(); + } + // compute hypothesis of the result + // not clear what 'result' is at this point. + // probably the proof at the top of the call + // XXX not clear why this is re-computed each time + // XXX moreover, m_units are guaranteed to be closed! + // XXX so no hypotheses are needed for them + add_hypotheses(result); + break; + case PR_LEMMA: { + SASSERT(m.get_num_parents(p) == 1); + tmp = m.get_parent(p, 0); + // eliminate hypothesis recursively in the proof of the lemma + elim(tmp); + expr_set* hyps = m_hypmap.find(tmp); + expr_set* new_hyps = 0; + // XXX if the proof is correct, the hypotheses of the tmp + // XXX should be exactly those of the consequence of the lemma + // XXX but if this code actually eliminates hypotheses, the set might be a subset + if (hyps) { + new_hyps = alloc(expr_set, *hyps); + } + expr* fact = m.get_fact(p); + // when hypothesis is a single literal of the form + // (or A B), and the fact of p is (or A B). + if (hyps && hyps->size() == 1 && in_hypotheses(fact, hyps)) { + m_literals.reset(); + m_literals.push_back(fact); + } + else { + get_literals(fact); + } + + // go over all the literals in the consequence of the lemma + for (unsigned i = 0; i < m_literals.size(); ++i) { + expr* e = m_literals[i]; + // if the literal is not in hypothesis, skip it + if (!in_hypotheses(e, hyps)) { + m_literals[i] = m_literals.back(); + m_literals.pop_back(); + --i; + } + // if the literal is in hypothesis remove it because + // it is not in hypothesis set of the lemma + // XXX but we assume that lemmas have empty hypothesis set. + // XXX eventually every element of new_hyps must be removed! + else { + SASSERT(new_hyps); + expr_ref not_e = complement_lit(e); + SASSERT(new_hyps->contains(not_e)); + new_hyps->remove(not_e); + } + } + // killed all hypotheses, so can stop at the lemma since + // we have a closed pf of false + if (m_literals.empty()) { + result = tmp; + } + else { + // create a new lemma, but might be re-creating existing one + expr_ref clause(m); + if (m_literals.size() == 1) { + clause = m_literals[0]; + } + else { + clause = m.mk_or(m_literals.size(), m_literals.c_ptr()); + } + tmp = m.mk_lemma(tmp, clause); + m_refs.push_back(tmp); + result = tmp; + } + if (new_hyps && new_hyps->empty()) { + dealloc(new_hyps); + new_hyps = 0; + } + m_hypmap.insert(result, new_hyps); + // might push 0 into m_hyprefs. No reason for that + m_hyprefs.push_back(new_hyps); + TRACE("proof_utils", + tout << "New lemma: " << mk_pp(m.get_fact(p), m) + << "\n==>\n" + << mk_pp(m.get_fact(result), m) << "\n"; + if (hyps) { + expr_set::iterator it = hyps->begin(); + expr_set::iterator end = hyps->end(); + for (; it != end; ++it) { + tout << "Hypothesis: " << mk_pp(*it, m) << "\n"; + } + }); + + break; + } + case PR_UNIT_RESOLUTION: { + proof_ref_vector parents(m); + // get the clause being resolved with + parents.push_back(m.get_parent(p, 0)); + // save state + push(); + bool found_false = false; + // for every derivation of a unit literal + for (unsigned i = 1; i < m.get_num_parents(p); ++i) { + // see if it derives false + tmp = m.get_parent(p, i); + elim(tmp); + if (m.is_false(m.get_fact(tmp))) { + // if derived false, the whole pf is false and we can bail out + result = tmp; + found_false = true; + break; + } + // -- otherwise, the fact has not changed. nothing to simplify + SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); + parents.push_back(tmp); + // remember that we have this derivation while we have not poped the trail + // but only if the proof is closed (i.e., a real unit) + if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) { + m_units.insert(m.get_fact(tmp), tmp); + m_units_trail.push_back(m.get_fact(tmp)); + } + } + if (found_false) { + pop(); + break; + } + // look at the clause being resolved with + tmp = m.get_parent(p, 0); + // remember its fact + expr* old_clause = m.get_fact(tmp); + // attempt to reduce its fact + elim(tmp); + // update parents + parents[0] = tmp; + // if the new fact is false, bail out + expr* clause = m.get_fact(tmp); + if (m.is_false(clause)) { + m_refs.push_back(tmp); + result = tmp; + pop(); + break; + } + // + // case where clause is a literal in the old clause. + // i.e., reduce multi-literal clause to a unit + // + if (is_literal_in_clause(clause, old_clause)) { + // if the resulting literal was resolved, get a pf of false and bail out + bool found = false; + for (unsigned i = 1; !found && i < parents.size(); ++i) { + if (m.is_complement(clause, m.get_fact(parents[i].get()))) { + parents[1] = parents[i].get(); + parents.resize(2); + result = m.mk_unit_resolution(parents.size(), parents.c_ptr()); + m_refs.push_back(result); + add_hypotheses(result); + found = true; + } + } + // else if the resulting literal is not resolved, it is the new consequence + if (!found) { + result = parents[0].get(); + } + pop(); + break; + } + // + // case where new clause is a subset of old clause. + // the literals in clause should be a subset of literals in old_clause. + // + get_literals(clause); + for (unsigned i = 1; i < parents.size(); ++i) { + bool found = false; + for (unsigned j = 0; j < m_literals.size(); ++j) { + if (m.is_complement(m_literals[j], m.get_fact(parents[i].get()))) { + found = true; + break; + } + } + if (!found) { + // literal was removed as hypothesis. + parents[i] = parents.back(); + parents.pop_back(); + --i; + } + } + if (parents.size() == 1) { + result = parents[0].get(); + } + else { + result = m.mk_unit_resolution(parents.size(), parents.c_ptr()); + m_refs.push_back(result); + add_hypotheses(result); + } + pop(); + break; + } + default: { + ptr_buffer args; + bool change = false; + bool found_false = false; + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + tmp = m.get_parent(p, i); + elim(tmp); + if (m.is_false(m.get_fact(tmp))) { + result = tmp; + found_false = true; + break; + } + // SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); + change = change || (tmp != m.get_parent(p, i)); + args.push_back(tmp); + } + if (found_false) { + break; + } + if (m.has_fact(p)) { + args.push_back(m.get_fact(p)); + } + if (change) { + tmp = m.mk_app(p->get_decl(), args.size(), args.c_ptr()); + m_refs.push_back(tmp); + } + else { + tmp = p; + } + result = tmp; + add_hypotheses(result); + break; + } + } + SASSERT(m_hypmap.contains(result)); + m_cache.insert(p, result); + p = result; + } + + bool is_literal_in_clause(expr* fml, expr* clause) { + if (!m.is_or(clause)) { + return false; + } + app* cl = to_app(clause); + for (unsigned i = 0; i < cl->get_num_args(); ++i) { + if (cl->get_arg(i) == fml) { + return true; + } + } + return false; + } +}; + +void proof_utils::reduce_hypotheses(proof_ref& pr) { + ast_manager& m = pr.get_manager(); + class reduce_hypotheses0 reduce(m); + reduce(pr); + CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";); +} + +class proof_is_closed { + ast_manager& m; + ptr_vector m_literals; + ast_mark m_visit; + + void reset() { + m_literals.reset(); + m_visit.reset(); + } + + bool check(proof* p) { + // really just a partial check because nodes may be visited + // already under a different lemma scope. + if (m_visit.is_marked(p)) { + return true; + } + bool result = false; + m_visit.mark(p, true); + switch(p->get_decl_kind()) { + case PR_LEMMA: { + unsigned sz = m_literals.size(); + expr* cls = m.get_fact(p); + m_literals.push_back(cls); + if (m.is_or(cls)) { + m_literals.append(to_app(cls)->get_num_args(), to_app(cls)->get_args()); + } + SASSERT(m.get_num_parents(p) == 1); + result = check(m.get_parent(p, 0)); + m_literals.resize(sz); + break; + } + case PR_HYPOTHESIS: { + expr* fact = m.get_fact(p); + for (unsigned i = 0; i < m_literals.size(); ++i) { + if (m.is_complement(m_literals[i], fact)) { + result = true; + break; + } + } + break; + } + default: + result = true; + for (unsigned i = 0; i < m.get_num_parents(p); ++i) { + if (!check(m.get_parent(p, i))) { + result = false; + break; + } + } + break; + } + + return result; + } + +public: + proof_is_closed(ast_manager& m): m(m) {} + + bool operator()(proof *p) { + bool ok = check(p); + reset(); + return ok; + } +}; + +bool proof_utils::is_closed(ast_manager& m, proof* p) { + proof_is_closed checker(m); + return checker(p); +} + + +static void permute_unit_resolution(expr_ref_vector& refs, obj_map& cache, proof_ref& pr) { + ast_manager& m = pr.get_manager(); + proof* pr2 = 0; + proof_ref_vector parents(m); + proof_ref prNew(pr); + if (cache.find(pr, pr2)) { + pr = pr2; + return; + } + + for (unsigned i = 0; i < m.get_num_parents(pr); ++i) { + prNew = m.get_parent(pr, i); + permute_unit_resolution(refs, cache, prNew); + parents.push_back(prNew); + } + + prNew = pr; + if (pr->get_decl_kind() == PR_UNIT_RESOLUTION && + parents[0]->get_decl_kind() == PR_TH_LEMMA) { + /* + Unit resolution: + T1: (or l_1 ... l_n l_1' ... l_m') + T2: (not l_1) + ... + T(n+1): (not l_n) + [unit-resolution T1 ... T(n+1)]: (or l_1' ... l_m') + Th lemma: + T1: (not l_1) + ... + Tn: (not l_n) + [th-lemma T1 ... Tn]: (or l_{n+1} ... l_m) + + Such that (or l_1 .. l_n l_{n+1} .. l_m) is a theory axiom. + + Implement conversion: + + T1 |- not l_1 ... Tn |- not l_n + ------------------------------- TH_LEMMA + (or k_1 .. k_m j_1 ... j_m) S1 |- not k_1 ... Sm |- not k_m + -------------------------------------------------------------- UNIT_RESOLUTION + (or j_1 .. j_m) + + + |-> + + T1 |- not l_1 ... Tn |- not l_n S1 |- not k_1 ... Sm |- not k_m + ---------------------------------------------------------------- TH_LEMMA + (or j_1 .. j_m) + + */ + proof_ref_vector premises(m); + proof* thLemma = parents[0].get(); + for (unsigned i = 0; i < m.get_num_parents(thLemma); ++i) { + premises.push_back(m.get_parent(thLemma, i)); + } + for (unsigned i = 1; i < parents.size(); ++i) { + premises.push_back(parents[i].get()); + } + parameter const* params = thLemma->get_decl()->get_parameters(); + unsigned num_params = thLemma->get_decl()->get_num_parameters(); + SASSERT(params[0].is_symbol()); + family_id tid = m.mk_family_id(params[0].get_symbol()); + SASSERT(tid != null_family_id); + // AG: This can break a theory lemma. In particular, for Farkas lemmas the coefficients + // AG: for the literals propagated from the unit resolution are missing. + // AG: Why is this a good thing to do? + // AG: This can lead to merging of the units with other terms in interpolation, + // AG: but without farkas coefficients this does not make sense + prNew = m.mk_th_lemma(tid, m.get_fact(pr), + premises.size(), premises.c_ptr(), num_params-1, params+1); + } + else { + ptr_vector args; + for (unsigned i = 0; i < parents.size(); ++i) { + args.push_back(parents[i].get()); + } + if (m.has_fact(pr)) { + args.push_back(m.get_fact(pr)); + } + prNew = m.mk_app(pr->get_decl(), args.size(), args.c_ptr()); + } + + cache.insert(pr, prNew); + refs.push_back(prNew); + pr = prNew; +} + + +// permute unit resolution over Theory lemmas to track premises. +void proof_utils::permute_unit_resolution(proof_ref& pr) { + expr_ref_vector refs(pr.get_manager()); + obj_map cache; + ::permute_unit_resolution(refs, cache, pr); +} + +class push_instantiations_up_cl { + ast_manager& m; +public: + push_instantiations_up_cl(ast_manager& m): m(m) {} + + void operator()(proof_ref& p) { + expr_ref_vector s0(m); + p = push(p, s0); + } + +private: + + proof* push(proof* p, expr_ref_vector const& sub) { + proof_ref_vector premises(m); + expr_ref conclusion(m); + svector > positions; + vector substs; + + if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) { + for (unsigned i = 0; i < premises.size(); ++i) { + compose(substs[i], sub); + premises[i] = push(premises[i].get(), substs[i]); + substs[i].reset(); + } + instantiate(sub, conclusion); + return + m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, + positions, + substs); + } + if (sub.empty()) { + return p; + } + if (m.is_modus_ponens(p)) { + SASSERT(m.get_num_parents(p) == 2); + proof* p0 = m.get_parent(p, 0); + proof* p1 = m.get_parent(p, 1); + if (m.get_fact(p0) == m.get_fact(p)) { + return push(p0, sub); + } + expr* e1, *e2; + if (m.is_rewrite(p1, e1, e2) && + is_quantifier(e1) && is_quantifier(e2) && + to_quantifier(e1)->get_num_decls() == to_quantifier(e2)->get_num_decls()) { + expr_ref r1(e1,m), r2(e2,m); + instantiate(sub, r1); + instantiate(sub, r2); + p1 = m.mk_rewrite(r1, r2); + return m.mk_modus_ponens(push(p0, sub), p1); + } + } + premises.push_back(p); + substs.push_back(sub); + conclusion = m.get_fact(p); + instantiate(sub, conclusion); + return m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, positions, substs); + } + + 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; + } + } + + void instantiate(expr_ref_vector const& sub, expr_ref& fml) { + if (sub.empty()) { + return; + } + if (!is_forall(fml)) { + return; + } + quantifier* q = to_quantifier(fml); + if (q->get_num_decls() != sub.size()) { + TRACE("proof_utils", tout << "quantifier has different number of variables than substitution"; + tout << mk_pp(q, m) << "\n"; + tout << sub.size() << "\n";); + return; + } + var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml); + } + +}; + +void proof_utils::push_instantiations_up(proof_ref& pr) { + push_instantiations_up_cl push(pr.get_manager()); + push(pr); +} + + diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 7963d52de..f813b96ad 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -16,8 +16,8 @@ Revision History: --*/ -#ifndef _PROOF_UTILS_H_ -#define _PROOF_UTILS_H_ +#ifndef PROOF_UTILS_H_ +#define PROOF_UTILS_H_ #include "ast/ast.h" /* @@ -39,4 +39,31 @@ private: void reduce_hypotheses(proof_ref &pr); +class proof_utils { +public: + /** + \brief reduce the set of hypotheses used in the proof. + */ + static void reduce_hypotheses(proof_ref& pr); + + /** + \brief Check that a proof does not contain open hypotheses. + */ + static bool is_closed(ast_manager& m, proof* p); + + /** + \brief Permute unit resolution rule with th-lemma + */ + static void permute_unit_resolution(proof_ref& pr); + + /** + \brief Push instantiations created in hyper-resolutions up to leaves. + This produces a "ground" proof where leaves are annotated by instantiations. + */ + static void push_instantiations_up(proof_ref& pr); + + +}; + + #endif diff --git a/src/muz/base/CMakeLists.txt b/src/muz/base/CMakeLists.txt index ec1ce47c3..6b0334664 100644 --- a/src/muz/base/CMakeLists.txt +++ b/src/muz/base/CMakeLists.txt @@ -10,7 +10,6 @@ z3_add_component(muz dl_rule_transformer.cpp dl_util.cpp hnf.cpp - proof_utils.cpp rule_properties.cpp COMPONENT_DEPENDENCIES aig_tactic diff --git a/src/muz/base/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp index ec999c05e..8f4f9c02d 100644 --- a/src/muz/base/dl_boogie_proof.cpp +++ b/src/muz/base/dl_boogie_proof.cpp @@ -53,7 +53,7 @@ Example from Boogie: #include "muz/base/dl_boogie_proof.h" #include "model/model_pp.h" -#include "muz/base/proof_utils.h" +#include "ast/proofs/proof_utils.h" #include "ast/ast_pp.h" #include "ast/ast_util.h" diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index d04e4037c..c560ee28e 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -11,7 +11,7 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2010-05-20. + Krystof Hoder 2010 Revision History: @@ -31,6 +31,7 @@ Revision History: #include "util/statistics.h" #include "util/stopwatch.h" #include "util/lbool.h" +#include "util/container_util.h" namespace datalog { @@ -381,129 +382,6 @@ namespace datalog { */ void apply_subst(expr_ref_vector& tgt, expr_ref_vector const& sub); - // ----------------------------------- - // - // container functions - // - // ----------------------------------- - - template - void set_intersection(Set1 & tgt, const Set2 & src) { - svector to_remove; - typename Set1::iterator vit = tgt.begin(); - typename Set1::iterator vend = tgt.end(); - for(;vit!=vend;++vit) { - typename Set1::data itm=*vit; - if(!src.contains(itm)) { - to_remove.push_back(itm); - } - } - while(!to_remove.empty()) { - tgt.remove(to_remove.back()); - to_remove.pop_back(); - } - } - - template - void set_difference(Set & tgt, const Set & to_remove) { - typename Set::iterator vit = to_remove.begin(); - typename Set::iterator vend = to_remove.end(); - for(;vit!=vend;++vit) { - typename Set::data itm=*vit; - tgt.remove(itm); - } - } - - template - void set_union(Set1 & tgt, const Set2 & to_add) { - typename Set2::iterator vit = to_add.begin(); - typename Set2::iterator vend = to_add.end(); - for(;vit!=vend;++vit) { - typename Set1::data itm=*vit; - tgt.insert(itm); - } - } - - void idx_set_union(idx_set & tgt, const idx_set & src); - - template - void unite_disjoint_maps(T & tgt, const T & src) { - typename T::iterator it = src.begin(); - typename T::iterator end = src.end(); - for(; it!=end; ++it) { - SASSERT(!tgt.contains(it->m_key)); - tgt.insert(it->m_key, it->m_value); - } - } - - template - void collect_map_range(T & acc, const U & map) { - typename U::iterator it = map.begin(); - typename U::iterator end = map.end(); - for(; it!=end; ++it) { - acc.push_back(it->m_value); - } - } - - - template - void print_container(const T & begin, const T & end, std::ostream & out) { - T it = begin; - out << "("; - bool first = true; - for(; it!=end; ++it) { - if(first) { first = false; } else { out << ","; } - out << (*it); - } - out << ")"; - } - - template - void print_container(const T & cont, std::ostream & out) { - print_container(cont.begin(), cont.end(), out); - } - - template - void print_container(const ref_vector & cont, std::ostream & out) { - print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out); - } - - template - void print_map(const T & cont, std::ostream & out) { - typename T::iterator it = cont.begin(); - typename T::iterator end = cont.end(); - out << "("; - bool first = true; - for(; it!=end; ++it) { - if(first) { first = false; } else { out << ","; } - out << it->m_key << "->" << it->m_value; - } - out << ")"; - } - - template - unsigned find_index(const It & begin, const It & end, const V & val) { - unsigned idx = 0; - It it = begin; - for(; it!=end; it++, idx++) { - if(*it==val) { - return idx; - } - } - return UINT_MAX; - } - - template - bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) { - T it1 = begin1; - U it2 = begin2; - for(; it1!=end1 && it2!=end2; ++it1, ++it2) { - if(*it1!=*it2) { - return false; - } - } - return it1==end1 && it2==end2; - } template bool vectors_equal(const T & c1, const U & c2) { @@ -521,6 +399,8 @@ namespace datalog { return true; } + void idx_set_union(idx_set & tgt, const idx_set & src); + template struct default_obj_chash { unsigned operator()(T const& cont, unsigned i) const { diff --git a/src/muz/base/proof_utils.cpp b/src/muz/base/proof_utils.cpp deleted file mode 100644 index 87355a07b..000000000 --- a/src/muz/base/proof_utils.cpp +++ /dev/null @@ -1,680 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include "muz/base/dl_util.h" -#include "muz/base/proof_utils.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/var_subst.h" - -class reduce_hypotheses0 { - typedef obj_hashtable expr_set; - ast_manager& m; - // reference for any expression created by the tranformation - expr_ref_vector m_refs; - // currently computed result - obj_map m_cache; - // map conclusions to closed proofs that derive them - obj_map m_units; - // currently active units - ptr_vector m_units_trail; - // size of m_units_trail at the last push - unsigned_vector m_limits; - // map from proofs to active hypotheses - obj_map m_hypmap; - // refernce train for hypotheses sets - ptr_vector m_hyprefs; - ptr_vector m_literals; - - void reset() { - m_refs.reset(); - m_cache.reset(); - m_units.reset(); - m_units_trail.reset(); - m_limits.reset(); - std::for_each(m_hyprefs.begin(), m_hyprefs.end(), delete_proc()); - m_hypmap.reset(); - m_hyprefs.reset(); - m_literals.reset(); - } - - void push() { - m_limits.push_back(m_units_trail.size()); - } - - void pop() { - unsigned sz = m_limits.back(); - while (m_units_trail.size() > sz) { - m_units.remove(m_units_trail.back()); - m_units_trail.pop_back(); - } - m_limits.pop_back(); - } - - void get_literals(expr* clause) { - m_literals.reset(); - if (m.is_or(clause)) { - m_literals.append(to_app(clause)->get_num_args(), to_app(clause)->get_args()); - } - else { - m_literals.push_back(clause); - } - } - - void add_hypotheses(proof* p) { - expr_set* hyps = 0; - bool inherited = false; - if (p->get_decl_kind() == PR_HYPOTHESIS) { - hyps = alloc(expr_set); - hyps->insert(m.get_fact(p)); - m_hyprefs.push_back(hyps); - } - else { - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - expr_set* hyps1 = m_hypmap.find(m.get_parent(p, i)); - if (hyps1) { - if (!hyps) { - hyps = hyps1; - inherited = true; - continue; - } - if (inherited) { - hyps = alloc(expr_set,*hyps); - m_hyprefs.push_back(hyps); - inherited = false; - } - datalog::set_union(*hyps, *hyps1); - } - } - } - m_hypmap.insert(p, hyps); - } - - expr_ref complement_lit(expr* e) { - expr* e1; - if (m.is_not(e, e1)) { - return expr_ref(e1, m); - } - else { - return expr_ref(m.mk_not(e), m); - } - } - - bool in_hypotheses(expr* e, expr_set* hyps) { - if (!hyps) { - return false; - } - expr_ref not_e = complement_lit(e); - return hyps->contains(not_e); - } - - bool contains_hypothesis(proof* p) { - ptr_vector todo; - ast_mark visit; - todo.push_back(p); - while (!todo.empty()) { - p = todo.back(); - todo.pop_back(); - if (visit.is_marked(p)) { - continue; - } - visit.mark(p, true); - if (PR_HYPOTHESIS == p->get_decl_kind()) { - return true; - } - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - todo.push_back(m.get_parent(p, i)); - } - } - return false; - } - - bool is_closed(proof* p) { - expr_set* hyps = m_hypmap.find(p); - return !hyps || hyps->empty(); - } - -public: - reduce_hypotheses0(ast_manager& m): m(m), m_refs(m) {} - - void operator()(proof_ref& pr) { - proof_ref tmp(m); - tmp = pr; - elim(pr); - reset(); - CTRACE("proof_utils", contains_hypothesis(pr), - tout << "Contains hypothesis:\n"; - tout << mk_ismt2_pp(tmp, m) << "\n====>\n"; - tout << mk_ismt2_pp(pr, m) << "\n";); - - } - - void elim(proof_ref& p) { - proof_ref tmp(m); - proof* result = p.get(); - if (m_cache.find(p, result)) { - p = result; - return; - } - //SASSERT (p.get () == result); - switch(p->get_decl_kind()) { - case PR_HYPOTHESIS: - // replace result by m_units[m.get_fact (p)] if defined - // AG: This is the main step. Replace a hypothesis by a derivation of its consequence - if (!m_units.find(m.get_fact(p), result)) { - // restore ther result back to p - result = p.get(); - } - // compute hypothesis of the result - // not clear what 'result' is at this point. - // probably the proof at the top of the call - // XXX not clear why this is re-computed each time - // XXX moreover, m_units are guaranteed to be closed! - // XXX so no hypotheses are needed for them - add_hypotheses(result); - break; - case PR_LEMMA: { - SASSERT(m.get_num_parents(p) == 1); - tmp = m.get_parent(p, 0); - // eliminate hypothesis recursively in the proof of the lemma - elim(tmp); - expr_set* hyps = m_hypmap.find(tmp); - expr_set* new_hyps = 0; - // XXX if the proof is correct, the hypotheses of the tmp - // XXX should be exactly those of the consequence of the lemma - // XXX but if this code actually eliminates hypotheses, the set might be a subset - if (hyps) { - new_hyps = alloc(expr_set, *hyps); - } - expr* fact = m.get_fact(p); - // when hypothesis is a single literal of the form - // (or A B), and the fact of p is (or A B). - if (hyps && hyps->size() == 1 && in_hypotheses(fact, hyps)) { - m_literals.reset(); - m_literals.push_back(fact); - } - else { - get_literals(fact); - } - - // go over all the literals in the consequence of the lemma - for (unsigned i = 0; i < m_literals.size(); ++i) { - expr* e = m_literals[i]; - // if the literal is not in hypothesis, skip it - if (!in_hypotheses(e, hyps)) { - m_literals[i] = m_literals.back(); - m_literals.pop_back(); - --i; - } - // if the literal is in hypothesis remove it because - // it is not in hypothesis set of the lemma - // XXX but we assume that lemmas have empty hypothesis set. - // XXX eventually every element of new_hyps must be removed! - else { - SASSERT(new_hyps); - expr_ref not_e = complement_lit(e); - SASSERT(new_hyps->contains(not_e)); - new_hyps->remove(not_e); - } - } - // killed all hypotheses, so can stop at the lemma since - // we have a closed pf of false - if (m_literals.empty()) { - result = tmp; - } - else { - // create a new lemma, but might be re-creating existing one - expr_ref clause(m); - if (m_literals.size() == 1) { - clause = m_literals[0]; - } - else { - clause = m.mk_or(m_literals.size(), m_literals.c_ptr()); - } - tmp = m.mk_lemma(tmp, clause); - m_refs.push_back(tmp); - result = tmp; - } - if (new_hyps && new_hyps->empty()) { - dealloc(new_hyps); - new_hyps = 0; - } - m_hypmap.insert(result, new_hyps); - // might push 0 into m_hyprefs. No reason for that - m_hyprefs.push_back(new_hyps); - TRACE("proof_utils", - tout << "New lemma: " << mk_pp(m.get_fact(p), m) - << "\n==>\n" - << mk_pp(m.get_fact(result), m) << "\n"; - if (hyps) { - expr_set::iterator it = hyps->begin(); - expr_set::iterator end = hyps->end(); - for (; it != end; ++it) { - tout << "Hypothesis: " << mk_pp(*it, m) << "\n"; - } - }); - - break; - } - case PR_UNIT_RESOLUTION: { - proof_ref_vector parents(m); - // get the clause being resolved with - parents.push_back(m.get_parent(p, 0)); - // save state - push(); - bool found_false = false; - // for every derivation of a unit literal - for (unsigned i = 1; i < m.get_num_parents(p); ++i) { - // see if it derives false - tmp = m.get_parent(p, i); - elim(tmp); - if (m.is_false(m.get_fact(tmp))) { - // if derived false, the whole pf is false and we can bail out - result = tmp; - found_false = true; - break; - } - // -- otherwise, the fact has not changed. nothing to simplify - SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); - parents.push_back(tmp); - // remember that we have this derivation while we have not poped the trail - // but only if the proof is closed (i.e., a real unit) - if (is_closed(tmp) && !m_units.contains(m.get_fact(tmp))) { - m_units.insert(m.get_fact(tmp), tmp); - m_units_trail.push_back(m.get_fact(tmp)); - } - } - if (found_false) { - pop(); - break; - } - // look at the clause being resolved with - tmp = m.get_parent(p, 0); - // remember its fact - expr* old_clause = m.get_fact(tmp); - // attempt to reduce its fact - elim(tmp); - // update parents - parents[0] = tmp; - // if the new fact is false, bail out - expr* clause = m.get_fact(tmp); - if (m.is_false(clause)) { - m_refs.push_back(tmp); - result = tmp; - pop(); - break; - } - // - // case where clause is a literal in the old clause. - // i.e., reduce multi-literal clause to a unit - // - if (is_literal_in_clause(clause, old_clause)) { - // if the resulting literal was resolved, get a pf of false and bail out - bool found = false; - for (unsigned i = 1; !found && i < parents.size(); ++i) { - if (m.is_complement(clause, m.get_fact(parents[i].get()))) { - parents[1] = parents[i].get(); - parents.resize(2); - result = m.mk_unit_resolution(parents.size(), parents.c_ptr()); - m_refs.push_back(result); - add_hypotheses(result); - found = true; - } - } - // else if the resulting literal is not resolved, it is the new consequence - if (!found) { - result = parents[0].get(); - } - pop(); - break; - } - // - // case where new clause is a subset of old clause. - // the literals in clause should be a subset of literals in old_clause. - // - get_literals(clause); - for (unsigned i = 1; i < parents.size(); ++i) { - bool found = false; - for (unsigned j = 0; j < m_literals.size(); ++j) { - if (m.is_complement(m_literals[j], m.get_fact(parents[i].get()))) { - found = true; - break; - } - } - if (!found) { - // literal was removed as hypothesis. - parents[i] = parents.back(); - parents.pop_back(); - --i; - } - } - if (parents.size() == 1) { - result = parents[0].get(); - } - else { - result = m.mk_unit_resolution(parents.size(), parents.c_ptr()); - m_refs.push_back(result); - add_hypotheses(result); - } - pop(); - break; - } - default: { - ptr_buffer args; - bool change = false; - bool found_false = false; - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - tmp = m.get_parent(p, i); - elim(tmp); - if (m.is_false(m.get_fact(tmp))) { - result = tmp; - found_false = true; - break; - } - // SASSERT(m.get_fact(tmp) == m.get_fact(m.get_parent(p, i))); - change = change || (tmp != m.get_parent(p, i)); - args.push_back(tmp); - } - if (found_false) { - break; - } - if (m.has_fact(p)) { - args.push_back(m.get_fact(p)); - } - if (change) { - tmp = m.mk_app(p->get_decl(), args.size(), args.c_ptr()); - m_refs.push_back(tmp); - } - else { - tmp = p; - } - result = tmp; - add_hypotheses(result); - break; - } - } - SASSERT(m_hypmap.contains(result)); - m_cache.insert(p, result); - p = result; - } - - bool is_literal_in_clause(expr* fml, expr* clause) { - if (!m.is_or(clause)) { - return false; - } - app* cl = to_app(clause); - for (unsigned i = 0; i < cl->get_num_args(); ++i) { - if (cl->get_arg(i) == fml) { - return true; - } - } - return false; - } -}; - -void proof_utils::reduce_hypotheses(proof_ref& pr) { - ast_manager& m = pr.get_manager(); - class reduce_hypotheses0 reduce(m); - reduce(pr); - CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";); -} - -class proof_is_closed { - ast_manager& m; - ptr_vector m_literals; - ast_mark m_visit; - - void reset() { - m_literals.reset(); - m_visit.reset(); - } - - bool check(proof* p) { - // really just a partial check because nodes may be visited - // already under a different lemma scope. - if (m_visit.is_marked(p)) { - return true; - } - bool result = false; - m_visit.mark(p, true); - switch(p->get_decl_kind()) { - case PR_LEMMA: { - unsigned sz = m_literals.size(); - expr* cls = m.get_fact(p); - m_literals.push_back(cls); - if (m.is_or(cls)) { - m_literals.append(to_app(cls)->get_num_args(), to_app(cls)->get_args()); - } - SASSERT(m.get_num_parents(p) == 1); - result = check(m.get_parent(p, 0)); - m_literals.resize(sz); - break; - } - case PR_HYPOTHESIS: { - expr* fact = m.get_fact(p); - for (unsigned i = 0; i < m_literals.size(); ++i) { - if (m.is_complement(m_literals[i], fact)) { - result = true; - break; - } - } - break; - } - default: - result = true; - for (unsigned i = 0; i < m.get_num_parents(p); ++i) { - if (!check(m.get_parent(p, i))) { - result = false; - break; - } - } - break; - } - - return result; - } - -public: - proof_is_closed(ast_manager& m): m(m) {} - - bool operator()(proof *p) { - bool ok = check(p); - reset(); - return ok; - } -}; - -bool proof_utils::is_closed(ast_manager& m, proof* p) { - proof_is_closed checker(m); - return checker(p); -} - - -static void permute_unit_resolution(expr_ref_vector& refs, obj_map& cache, proof_ref& pr) { - ast_manager& m = pr.get_manager(); - proof* pr2 = 0; - proof_ref_vector parents(m); - proof_ref prNew(pr); - if (cache.find(pr, pr2)) { - pr = pr2; - return; - } - - for (unsigned i = 0; i < m.get_num_parents(pr); ++i) { - prNew = m.get_parent(pr, i); - permute_unit_resolution(refs, cache, prNew); - parents.push_back(prNew); - } - - prNew = pr; - if (pr->get_decl_kind() == PR_UNIT_RESOLUTION && - parents[0]->get_decl_kind() == PR_TH_LEMMA) { - /* - Unit resolution: - T1: (or l_1 ... l_n l_1' ... l_m') - T2: (not l_1) - ... - T(n+1): (not l_n) - [unit-resolution T1 ... T(n+1)]: (or l_1' ... l_m') - Th lemma: - T1: (not l_1) - ... - Tn: (not l_n) - [th-lemma T1 ... Tn]: (or l_{n+1} ... l_m) - - Such that (or l_1 .. l_n l_{n+1} .. l_m) is a theory axiom. - - Implement conversion: - - T1 |- not l_1 ... Tn |- not l_n - ------------------------------- TH_LEMMA - (or k_1 .. k_m j_1 ... j_m) S1 |- not k_1 ... Sm |- not k_m - -------------------------------------------------------------- UNIT_RESOLUTION - (or j_1 .. j_m) - - - |-> - - T1 |- not l_1 ... Tn |- not l_n S1 |- not k_1 ... Sm |- not k_m - ---------------------------------------------------------------- TH_LEMMA - (or j_1 .. j_m) - - */ - proof_ref_vector premises(m); - proof* thLemma = parents[0].get(); - for (unsigned i = 0; i < m.get_num_parents(thLemma); ++i) { - premises.push_back(m.get_parent(thLemma, i)); - } - for (unsigned i = 1; i < parents.size(); ++i) { - premises.push_back(parents[i].get()); - } - parameter const* params = thLemma->get_decl()->get_parameters(); - unsigned num_params = thLemma->get_decl()->get_num_parameters(); - SASSERT(params[0].is_symbol()); - family_id tid = m.mk_family_id(params[0].get_symbol()); - SASSERT(tid != null_family_id); - // AG: This can break a theory lemma. In particular, for Farkas lemmas the coefficients - // AG: for the literals propagated from the unit resolution are missing. - // AG: Why is this a good thing to do? - // AG: This can lead to merging of the units with other terms in interpolation, - // AG: but without farkas coefficients this does not make sense - prNew = m.mk_th_lemma(tid, m.get_fact(pr), - premises.size(), premises.c_ptr(), num_params-1, params+1); - } - else { - ptr_vector args; - for (unsigned i = 0; i < parents.size(); ++i) { - args.push_back(parents[i].get()); - } - if (m.has_fact(pr)) { - args.push_back(m.get_fact(pr)); - } - prNew = m.mk_app(pr->get_decl(), args.size(), args.c_ptr()); - } - - cache.insert(pr, prNew); - refs.push_back(prNew); - pr = prNew; -} - - -// permute unit resolution over Theory lemmas to track premises. -void proof_utils::permute_unit_resolution(proof_ref& pr) { - expr_ref_vector refs(pr.get_manager()); - obj_map cache; - ::permute_unit_resolution(refs, cache, pr); -} - -class push_instantiations_up_cl { - ast_manager& m; -public: - push_instantiations_up_cl(ast_manager& m): m(m) {} - - void operator()(proof_ref& p) { - expr_ref_vector s0(m); - p = push(p, s0); - } - -private: - - proof* push(proof* p, expr_ref_vector const& sub) { - proof_ref_vector premises(m); - expr_ref conclusion(m); - svector > positions; - vector substs; - - if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) { - for (unsigned i = 0; i < premises.size(); ++i) { - compose(substs[i], sub); - premises[i] = push(premises[i].get(), substs[i]); - substs[i].reset(); - } - instantiate(sub, conclusion); - return - m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, - positions, - substs); - } - if (sub.empty()) { - return p; - } - if (m.is_modus_ponens(p)) { - SASSERT(m.get_num_parents(p) == 2); - proof* p0 = m.get_parent(p, 0); - proof* p1 = m.get_parent(p, 1); - if (m.get_fact(p0) == m.get_fact(p)) { - return push(p0, sub); - } - expr* e1, *e2; - if (m.is_rewrite(p1, e1, e2) && - is_quantifier(e1) && is_quantifier(e2) && - to_quantifier(e1)->get_num_decls() == to_quantifier(e2)->get_num_decls()) { - expr_ref r1(e1,m), r2(e2,m); - instantiate(sub, r1); - instantiate(sub, r2); - p1 = m.mk_rewrite(r1, r2); - return m.mk_modus_ponens(push(p0, sub), p1); - } - } - premises.push_back(p); - substs.push_back(sub); - conclusion = m.get_fact(p); - instantiate(sub, conclusion); - return m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, positions, substs); - } - - 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; - } - } - - void instantiate(expr_ref_vector const& sub, expr_ref& fml) { - if (sub.empty()) { - return; - } - if (!is_forall(fml)) { - return; - } - quantifier* q = to_quantifier(fml); - if (q->get_num_decls() != sub.size()) { - TRACE("proof_utils", tout << "quantifier has different number of variables than substitution"; - tout << mk_pp(q, m) << "\n"; - tout << sub.size() << "\n";); - return; - } - var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml); - } - -}; - -void proof_utils::push_instantiations_up(proof_ref& pr) { - push_instantiations_up_cl push(pr.get_manager()); - push(pr); -} - - diff --git a/src/muz/base/proof_utils.h b/src/muz/base/proof_utils.h deleted file mode 100644 index 0db831c4f..000000000 --- a/src/muz/base/proof_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - proof_utils.h - -Abstract: - - Utilities for transforming proofs. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-10-12. - -Revision History: - ---*/ -#ifndef PROOF_UTILS_H_ -#define PROOF_UTILS_H_ - -class proof_utils { -public: - /** - \brief reduce the set of hypotheses used in the proof. - */ - static void reduce_hypotheses(proof_ref& pr); - - /** - \brief Check that a proof does not contain open hypotheses. - */ - static bool is_closed(ast_manager& m, proof* p); - - /** - \brief Permute unit resolution rule with th-lemma - */ - static void permute_unit_resolution(proof_ref& pr); - - /** - \brief Push instantiations created in hyper-resolutions up to leaves. - This produces a "ground" proof where leaves are annotated by instantiations. - */ - static void push_instantiations_up(proof_ref& pr); - - -}; - -#endif diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index a1878dc7a..37d80e2d6 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -43,7 +43,6 @@ Notes: #include "ast/ast_ll_pp.h" #include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" -#include "muz/base/proof_utils.h" #include "muz/base/dl_boogie_proof.h" #include "ast/scoped_proof.h" #include "tactic/core/blast_term_ite_tactic.h" diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 4f47cb554..4a77d2f5f 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -31,7 +31,7 @@ Revision History: #include "ast/rewriter/th_rewriter.h" #include "ast/ast_ll_pp.h" #include "tactic/arith/arith_bounds_tactic.h" -#include "muz/base/proof_utils.h" +#include "ast/proofs/proof_utils.h" #include "ast/reg_decl_plugins.h" @@ -733,8 +733,8 @@ namespace pdr { } else { expr_set* hyps3 = alloc(expr_set); - datalog::set_union(*hyps3, *hyps); - datalog::set_union(*hyps3, *hyps2); + set_union(*hyps3, *hyps); + set_union(*hyps3, *hyps2); hyps = hyps3; hyprefs.push_back(hyps); } @@ -795,7 +795,7 @@ namespace pdr { case PR_LEMMA: { expr_set* hyps2 = alloc(expr_set); hyprefs.push_back(hyps2); - datalog::set_union(*hyps2, *hyps); + set_union(*hyps2, *hyps); hyps = hyps2; expr* fml = m.get_fact(p); hyps->remove(fml); diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index b17d3f8b6..094379a0b 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -81,7 +81,7 @@ namespace pdr { m_gen(n, core0, uses_level1); new_cores.push_back(std::make_pair(core0, uses_level1)); obj_hashtable core_exprs, core1_exprs; - datalog::set_union(core_exprs, core0); + set_union(core_exprs, core0); for (unsigned i = 0; i < old_core.size(); ++i) { expr* lit = old_core[i].get(); if (core_exprs.contains(lit)) { @@ -94,8 +94,8 @@ namespace pdr { if (core1.size() < old_core.size()) { new_cores.push_back(std::make_pair(core1, uses_level1)); core1_exprs.reset(); - datalog::set_union(core1_exprs, core1); - datalog::set_intersection(core_exprs, core1_exprs); + set_union(core1_exprs, core1); + set_intersection(core_exprs, core1_exprs); } } } diff --git a/src/muz/spacer/spacer_farkas_learner.cpp b/src/muz/spacer/spacer_farkas_learner.cpp index 47bc474ef..d97bee49f 100644 --- a/src/muz/spacer/spacer_farkas_learner.cpp +++ b/src/muz/spacer/spacer_farkas_learner.cpp @@ -31,7 +31,7 @@ Revision History: #include "muz/spacer/spacer_farkas_learner.h" #include "ast/rewriter/th_rewriter.h" #include "ast/ast_ll_pp.h" -#include "muz/base/proof_utils.h" +#include "ast/proofs/proof_utils.h" #include "ast/reg_decl_plugins.h" #include "smt/smt_farkas_util.h" @@ -231,8 +231,8 @@ void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector hyps = hyps2; } else { expr_set* hyps3 = alloc(expr_set); - datalog::set_union(*hyps3, *hyps); - datalog::set_union(*hyps3, *hyps2); + set_union(*hyps3, *hyps); + set_union(*hyps3, *hyps2); hyps = hyps3; hyprefs.push_back(hyps); } @@ -291,7 +291,7 @@ void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector case PR_LEMMA: { expr_set* hyps2 = alloc(expr_set); hyprefs.push_back(hyps2); - datalog::set_union(*hyps2, *hyps); + set_union(*hyps2, *hyps); hyps = hyps2; expr* fml = m.get_fact(p); hyps->remove(fml); diff --git a/src/muz/spacer/spacer_legacy_frames.cpp b/src/muz/spacer/spacer_legacy_frames.cpp index dd2a16abd..679736add 100644 --- a/src/muz/spacer/spacer_legacy_frames.cpp +++ b/src/muz/spacer/spacer_legacy_frames.cpp @@ -25,7 +25,7 @@ #include "ast/ast_util.h" #include "ast/proofs/proof_checker.h" #include "smt/smt_value_sort.h" -#include "muz/base/proof_utils.h" +#include "ast/proofs/proof_utils.h" #include "ast/scoped_proof.h" #include "muz/spacer/spacer_qe_project.h" #include "tactic/core/blast_term_ite_tactic.h" From db65cc007ad91bccb8815d0012be00c3b061290e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 10:27:48 -0700 Subject: [PATCH 25/57] move more proof utils Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/ast/proofs/proof_utils.h | 169 ++++++++++++++++++++++- src/muz/spacer/spacer_virtual_solver.cpp | 164 +--------------------- 3 files changed, 170 insertions(+), 165 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index ddf439e10..6e7024b3f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -43,7 +43,7 @@ def init_project_def(): add_lib('cmd_context', ['solver', 'rewriter', 'interp']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') - add_lib('proofs', ['rewriter'], 'ast/proofs') + add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index f813b96ad..4152bca92 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2017 Arie Gurfinkel +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,6 +11,7 @@ Abstract: Author: Bernhard Gleiss Arie Gurfinkel + Nikolaj Bjorner Revision History: @@ -65,5 +66,171 @@ public: }; +#include "ast/rewriter/bool_rewriter.h" +class elim_aux_assertions { + + static bool matches_fact(expr_ref_vector &args, expr* &match) { + ast_manager &m = args.get_manager(); + expr *fact = args.back(); + for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) { + expr *arg = args.get(i); + if (m.is_proof(arg) && + m.has_fact(to_app(arg)) && + m.get_fact(to_app(arg)) == fact) { + match = arg; + return true; + } + } + return false; + } + + app_ref m_aux; +public: + elim_aux_assertions(app_ref aux) : m_aux(aux) {} + + void mk_or_core(expr_ref_vector &args, expr_ref &res) + { + ast_manager &m = args.get_manager(); + unsigned j = 0; + for (unsigned i = 0, sz = args.size(); i < sz; ++i) { + if (m.is_false(args.get(i))) { continue; } + if (i != j) { args [j] = args.get(i); } + ++j; + } + SASSERT(j >= 1); + res = j > 1 ? m.mk_or(j, args.c_ptr()) : args.get(0); + } + + void mk_app(func_decl *decl, expr_ref_vector &args, expr_ref &res) + { + ast_manager &m = args.get_manager(); + bool_rewriter brwr(m); + + if (m.is_or(decl)) + { mk_or_core(args, res); } + else if (m.is_iff(decl) && args.size() == 2) + // avoiding simplifying equalities. In particular, + // we don't want (= (not a) (not b)) to be reduced to (= a b) + { res = m.mk_iff(args.get(0), args.get(1)); } + else + { brwr.mk_app(decl, args.size(), args.c_ptr(), res); } + } + + void operator()(ast_manager &m, proof *pr, proof_ref &res) + { + DEBUG_CODE(proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(pr, side)); + ); + obj_map cache; + bool_rewriter brwr(m); + + // for reference counting of new proofs + app_ref_vector pinned(m); + + ptr_vector todo; + todo.push_back(pr); + + expr_ref not_aux(m); + not_aux = m.mk_not(m_aux); + + expr_ref_vector args(m); + + while (!todo.empty()) { + app *p, *r; + expr *a; + + p = todo.back(); + if (cache.find(pr, r)) { + todo.pop_back(); + continue; + } + + SASSERT(!todo.empty() || pr == p); + bool dirty = false; + unsigned todo_sz = todo.size(); + args.reset(); + for (unsigned i = 0, sz = p->get_num_args(); i < sz; ++i) { + expr* arg = p->get_arg(i); + if (arg == m_aux.get()) { + dirty = true; + args.push_back(m.mk_true()); + } else if (arg == not_aux.get()) { + dirty = true; + args.push_back(m.mk_false()); + } + // skip (asserted m_aux) + else if (m.is_asserted(arg, a) && a == m_aux.get()) { + dirty = true; + } + // skip (hypothesis m_aux) + else if (m.is_hypothesis(arg, a) && a == m_aux.get()) { + dirty = true; + } else if (is_app(arg) && cache.find(to_app(arg), r)) { + dirty |= (arg != r); + args.push_back(r); + } else if (is_app(arg)) + { todo.push_back(to_app(arg)); } + else + // -- not an app + { args.push_back(arg); } + + } + if (todo_sz < todo.size()) { + // -- process parents + args.reset(); + continue; + } + + // ready to re-create + app_ref newp(m); + if (!dirty) { newp = p; } + else if (m.is_unit_resolution(p)) { + if (args.size() == 2) + // unit resolution with m_aux that got collapsed to nothing + { newp = to_app(args.get(0)); } + else { + ptr_vector parents; + for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) + { parents.push_back(to_app(args.get(i))); } + SASSERT(parents.size() == args.size() - 1); + newp = m.mk_unit_resolution(parents.size(), parents.c_ptr()); + // XXX the old and new facts should be + // equivalent. The test here is much + // stronger. It might need to be relaxed. + SASSERT(m.get_fact(newp) == args.back()); + pinned.push_back(newp); + } + } else if (matches_fact(args, a)) { + newp = to_app(a); + } else { + expr_ref papp(m); + mk_app(p->get_decl(), args, papp); + newp = to_app(papp.get()); + pinned.push_back(newp); + } + cache.insert(p, newp); + todo.pop_back(); + CTRACE("virtual", + p->get_decl_kind() == PR_TH_LEMMA && + p->get_decl()->get_parameter(0).get_symbol() == "arith" && + p->get_decl()->get_num_parameters() > 1 && + p->get_decl()->get_parameter(1).get_symbol() == "farkas", + tout << "Old pf: " << mk_pp(p, m) << "\n" + << "New pf: " << mk_pp(newp, m) << "\n";); + } + + proof *r; + VERIFY(cache.find(pr, r)); + + DEBUG_CODE( + proof_checker pc(m); + expr_ref_vector side(m); + SASSERT(pc.check(r, side)); + ); + + res = r ; + } +}; #endif diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 87a21336c..891256eed 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -24,6 +24,7 @@ Notes: #include "ast/rewriter/bool_rewriter.h" #include "ast/proofs/proof_checker.h" +#include "ast/proofs/proof_utils.h" #include "ast/scoped_proof.h" @@ -64,174 +65,11 @@ virtual_solver::~virtual_solver() } namespace { -static bool matches_fact(expr_ref_vector &args, expr* &match) -{ - ast_manager &m = args.get_manager(); - expr *fact = args.back(); - for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) { - expr *arg = args.get(i); - if (m.is_proof(arg) && - m.has_fact(to_app(arg)) && - m.get_fact(to_app(arg)) == fact) { - match = arg; - return true; - } - } - return false; -} // TBD: move to ast/proofs/elim_aux_assertions -class elim_aux_assertions { - app_ref m_aux; -public: - elim_aux_assertions(app_ref aux) : m_aux(aux) {} - void mk_or_core(expr_ref_vector &args, expr_ref &res) - { - ast_manager &m = args.get_manager(); - unsigned j = 0; - for (unsigned i = 0, sz = args.size(); i < sz; ++i) { - if (m.is_false(args.get(i))) { continue; } - if (i != j) { args [j] = args.get(i); } - ++j; - } - SASSERT(j >= 1); - res = j > 1 ? m.mk_or(j, args.c_ptr()) : args.get(0); - } - - void mk_app(func_decl *decl, expr_ref_vector &args, expr_ref &res) - { - ast_manager &m = args.get_manager(); - bool_rewriter brwr(m); - - if (m.is_or(decl)) - { mk_or_core(args, res); } - else if (m.is_iff(decl) && args.size() == 2) - // avoiding simplifying equalities. In particular, - // we don't want (= (not a) (not b)) to be reduced to (= a b) - { res = m.mk_iff(args.get(0), args.get(1)); } - else - { brwr.mk_app(decl, args.size(), args.c_ptr(), res); } - } - - void operator()(ast_manager &m, proof *pr, proof_ref &res) - { - DEBUG_CODE(proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(pr, side)); - ); - obj_map cache; - bool_rewriter brwr(m); - - // for reference counting of new proofs - app_ref_vector pinned(m); - - ptr_vector todo; - todo.push_back(pr); - - expr_ref not_aux(m); - not_aux = m.mk_not(m_aux); - - expr_ref_vector args(m); - - while (!todo.empty()) { - app *p, *r; - expr *a; - - p = todo.back(); - if (cache.find(pr, r)) { - todo.pop_back(); - continue; - } - - SASSERT(!todo.empty() || pr == p); - bool dirty = false; - unsigned todo_sz = todo.size(); - args.reset(); - for (unsigned i = 0, sz = p->get_num_args(); i < sz; ++i) { - expr* arg = p->get_arg(i); - if (arg == m_aux.get()) { - dirty = true; - args.push_back(m.mk_true()); - } else if (arg == not_aux.get()) { - dirty = true; - args.push_back(m.mk_false()); - } - // skip (asserted m_aux) - else if (m.is_asserted(arg, a) && a == m_aux.get()) { - dirty = true; - } - // skip (hypothesis m_aux) - else if (m.is_hypothesis(arg, a) && a == m_aux.get()) { - dirty = true; - } else if (is_app(arg) && cache.find(to_app(arg), r)) { - dirty |= (arg != r); - args.push_back(r); - } else if (is_app(arg)) - { todo.push_back(to_app(arg)); } - else - // -- not an app - { args.push_back(arg); } - - } - if (todo_sz < todo.size()) { - // -- process parents - args.reset(); - continue; - } - - // ready to re-create - app_ref newp(m); - if (!dirty) { newp = p; } - else if (m.is_unit_resolution(p)) { - if (args.size() == 2) - // unit resolution with m_aux that got collapsed to nothing - { newp = to_app(args.get(0)); } - else { - ptr_vector parents; - for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) - { parents.push_back(to_app(args.get(i))); } - SASSERT(parents.size() == args.size() - 1); - newp = m.mk_unit_resolution(parents.size(), parents.c_ptr()); - // XXX the old and new facts should be - // equivalent. The test here is much - // stronger. It might need to be relaxed. - SASSERT(m.get_fact(newp) == args.back()); - pinned.push_back(newp); - } - } else if (matches_fact(args, a)) { - newp = to_app(a); - } else { - expr_ref papp(m); - mk_app(p->get_decl(), args, papp); - newp = to_app(papp.get()); - pinned.push_back(newp); - } - cache.insert(p, newp); - todo.pop_back(); - CTRACE("virtual", - p->get_decl_kind() == PR_TH_LEMMA && - p->get_decl()->get_parameter(0).get_symbol() == "arith" && - p->get_decl()->get_num_parameters() > 1 && - p->get_decl()->get_parameter(1).get_symbol() == "farkas", - tout << "Old pf: " << mk_pp(p, m) << "\n" - << "New pf: " << mk_pp(newp, m) << "\n";); - } - - proof *r; - VERIFY(cache.find(pr, r)); - - DEBUG_CODE( - proof_checker pc(m); - expr_ref_vector side(m); - SASSERT(pc.check(r, side)); - ); - - res = r ; - } -}; } proof *virtual_solver::get_proof() From 48d144a6dda2d041811466694547f67b436f24c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 12:51:47 -0700 Subject: [PATCH 26/57] missing file Signed-off-by: Nikolaj Bjorner --- src/ast/proofs/proof_utils.cpp | 3 +- src/ast/proofs/proof_utils.h | 2 +- src/muz/spacer/spacer_virtual_solver.cpp | 2 - src/muz/spacer/spacer_virtual_solver.h | 6 +- src/util/container_util.h | 121 +++++++++++++++++++++++ 5 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 src/util/container_util.h diff --git a/src/ast/proofs/proof_utils.cpp b/src/ast/proofs/proof_utils.cpp index b6c8b58d7..58500cb79 100644 --- a/src/ast/proofs/proof_utils.cpp +++ b/src/ast/proofs/proof_utils.cpp @@ -20,10 +20,10 @@ Revision History: #include "ast/ast_pp.h" #include "ast/proofs/proof_utils.h" #include "ast/proofs/proof_checker.h" +#include "ast/rewriter/var_subst.h" #include "util/container_util.h" - proof_post_order::proof_post_order(proof* root, ast_manager& manager) : m(manager) {m_todo.push_back(root);} @@ -336,7 +336,6 @@ void reduce_hypotheses(proof_ref &pr) { #include "ast/ast_smt2_pp.h" -#include "ast/rewriter/var_subst.h" class reduce_hypotheses0 { typedef obj_hashtable expr_set; diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 4152bca92..9823acb92 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -20,6 +20,7 @@ Revision History: #ifndef PROOF_UTILS_H_ #define PROOF_UTILS_H_ #include "ast/ast.h" +#include "ast/rewriter/bool_rewriter.h" /* * iterator, which traverses the proof in depth-first post-order. @@ -66,7 +67,6 @@ public: }; -#include "ast/rewriter/bool_rewriter.h" class elim_aux_assertions { static bool matches_fact(expr_ref_vector &args, expr* &match) { diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 891256eed..89b9fb531 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -244,7 +244,6 @@ void virtual_solver::refresh() m_head = 0; } -#ifdef NOT_USED_ANYWHERE void virtual_solver::reset() { SASSERT(!m_pushed); @@ -252,7 +251,6 @@ void virtual_solver::reset() m_assertions.reset(); m_factory.refresh(); } -#endif void virtual_solver::get_labels(svector &r) { diff --git a/src/muz/spacer/spacer_virtual_solver.h b/src/muz/spacer/spacer_virtual_solver.h index 3ccd89ef5..fed64c589 100644 --- a/src/muz/spacer/spacer_virtual_solver.h +++ b/src/muz/spacer/spacer_virtual_solver.h @@ -91,9 +91,7 @@ public: virtual void set_produce_models(bool f); virtual bool get_produce_models(); virtual smt_params &fparams(); -#ifdef NOT_USED_ANYWHERE virtual void reset(); -#endif virtual void set_progress_callback(progress_callback *callback) {UNREACHABLE();} @@ -135,6 +133,9 @@ private: void refresh(); + + smt_params &fparams() { return m_fparams; } + public: virtual_solver_factory(ast_manager &mgr, smt_params &fparams); virtual ~virtual_solver_factory(); @@ -145,7 +146,6 @@ public: void collect_param_descrs(param_descrs &r) { /* empty */ } void set_produce_models(bool f) { m_fparams.m_model = f; } bool get_produce_models() { return m_fparams.m_model; } - smt_params &fparams() { return m_fparams; } }; } diff --git a/src/util/container_util.h b/src/util/container_util.h new file mode 100644 index 000000000..7bbc3fb08 --- /dev/null +++ b/src/util/container_util.h @@ -0,0 +1,121 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + container_util.h + +Abstract: + + Useful functions for containers + +Author: + + Krystof Hoder, Nikolaj Bjorner 2017-10-24 + +Revision History: + + Extracted from dl_util.h + +--*/ + +#ifndef CONTAINUR_UTIL_H +#define CONTAINER_UTIL_H_ + +// ----------------------------------- +// +// container functions +// +// ----------------------------------- + +template + void set_intersection(Set1 & tgt, const Set2 & src) { + svector to_remove; + for (Set1::data itm : tgt) + if (!src.contains(itm)) + to_remove.push_back(itm); + while (!to_remove.empty()) { + tgt.remove(to_remove.back()); + to_remove.pop_back(); + } +} + +template +void set_difference(Set & tgt, const Set & to_remove) { + for (auto const& itm : to_remove) + tgt.remove(itm); +} + +template +void set_union(Set1 & tgt, const Set2 & to_add) { + for (auto const& itm : to_add) + tgt.insert(itm); +} + +template +void unite_disjoint_maps(T & tgt, const T & src) { + for (auto const& kv : src) { + SASSERT(!tgt.contains(kv.m_key)); + tgt.insert(kv.m_key, kv.m_value); + } +} + +template +void collect_map_range(T & acc, const U & map) { + for (auto const& kv : map) + acc.push_back(kv.m_value); +} + + +template +void print_container(const T & begin, const T & end, std::ostream & out) { + T it = begin; + out << "("; + bool first = true; + for(; it!=end; ++it) { + if(first) { first = false; } else { out << ","; } + out << (*it); + } + out << ")"; +} + +template +void print_container(const T & cont, std::ostream & out) { + print_container(cont.begin(), cont.end(), out); +} + +template +void print_container(const ref_vector & cont, std::ostream & out) { + print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out); +} + +template +void print_map(const T & cont, std::ostream & out) { + out << "("; + bool first = true; + for (auto const& kv : cont) { + if (first) { first = false; } else { out << ","; } + out << kv.m_key << "->" << kv.m_value; + } + out << ")"; +} + +template +unsigned find_index(const It & begin, const It & end, const V & val) { + for (unsigned idx = 0, It it = begin; it != end; it++, idx++) { + if (*it == val) { + return idx; + } + } + return UINT_MAX; +} + +template +bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) { + T it1 = begin1; + U it2 = begin2; + for (; it1 != end1 && it2 != end2 && *it1 == *it2; ++it1, ++it2) {}; + return it1 == end1 && it2 == end2; +} + +#endif From 6300a78b82e46e887666a2386a020acd1dfd8059 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 12:57:30 -0700 Subject: [PATCH 27/57] more build errors in debug mode Signed-off-by: Nikolaj Bjorner --- src/ast/proofs/proof_utils.h | 2 ++ src/cmd_context/cmd_context.cpp | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ast/proofs/proof_utils.h b/src/ast/proofs/proof_utils.h index 9823acb92..b953c834d 100644 --- a/src/ast/proofs/proof_utils.h +++ b/src/ast/proofs/proof_utils.h @@ -20,7 +20,9 @@ Revision History: #ifndef PROOF_UTILS_H_ #define PROOF_UTILS_H_ #include "ast/ast.h" +#include "ast/ast_pp.h" #include "ast/rewriter/bool_rewriter.h" +#include "ast/proofs/proof_checker.h" /* * iterator, which traverses the proof in depth-first post-order. diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 77dce80c8..f27d8e681 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1053,6 +1053,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg func_decls fs; if (!m_func_decls.find(s, fs)) { if (num_args == 0) { + //UNREACHABLE(); throw cmd_exception("unknown constant ", s); } else @@ -1063,16 +1064,20 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg if (fs.more_than_one()) throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disumbiguate ", s); func_decl * f = fs.first(); - if (f == 0) + if (f == 0) { + //UNREACHABLE(); throw cmd_exception("unknown constant ", s); + } if (f->get_arity() != 0) throw cmd_exception("invalid function application, missing arguments ", s); result = m().mk_const(f); } else { func_decl * f = fs.find(m(), num_args, args, range); - if (f == 0) + if (f == 0) { + //UNREACHABLE(); throw cmd_exception("unknown constant ", s); + } if (well_sorted_check_enabled()) m().check_sort(f, num_args, args); result = m().mk_app(f, num_args, args); From 31dfc0c610ed8a38acfde3e41c94213cddf59c21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 13:20:19 -0700 Subject: [PATCH 28/57] fix build, fix #1322 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 18 ++++++++++++++---- src/util/container_util.h | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index f27d8e681..a1e7a4745 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1053,7 +1053,6 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg func_decls fs; if (!m_func_decls.find(s, fs)) { if (num_args == 0) { - //UNREACHABLE(); throw cmd_exception("unknown constant ", s); } else @@ -1065,7 +1064,6 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as ) to disumbiguate ", s); func_decl * f = fs.first(); if (f == 0) { - //UNREACHABLE(); throw cmd_exception("unknown constant ", s); } if (f->get_arity() != 0) @@ -1075,8 +1073,20 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg else { func_decl * f = fs.find(m(), num_args, args, range); if (f == 0) { - //UNREACHABLE(); - throw cmd_exception("unknown constant ", s); + std::ostringstream buffer; + buffer << "unknown constant " << s << " "; + buffer << " ("; + bool first = true; + for (unsigned i = 0; i < num_args; ++i, first = false) { + if (!first) buffer << " "; + buffer << mk_pp(m().get_sort(args[i]), m()); + } + buffer << ") "; + if (range) buffer << mk_pp(range, m()) << " "; + for (unsigned i = 0; i < fs.get_num_entries(); ++i) { + buffer << "\ndeclared: " << mk_pp(fs.get_entry(i), m()) << " "; + } + throw cmd_exception(buffer.str().c_str()); } if (well_sorted_check_enabled()) m().check_sort(f, num_args, args); diff --git a/src/util/container_util.h b/src/util/container_util.h index 7bbc3fb08..3b287ad51 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -31,7 +31,7 @@ Revision History: template void set_intersection(Set1 & tgt, const Set2 & src) { svector to_remove; - for (Set1::data itm : tgt) + for (auto const& itm : tgt) if (!src.contains(itm)) to_remove.push_back(itm); while (!to_remove.empty()) { From ee320fa0250c792a7c82baf0f50c25a2a2aa28ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 13:32:40 -0700 Subject: [PATCH 29/57] fix build errors Signed-off-by: Nikolaj Bjorner --- src/util/container_util.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/container_util.h b/src/util/container_util.h index 3b287ad51..f921b7b1d 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -19,7 +19,7 @@ Revision History: --*/ -#ifndef CONTAINUR_UTIL_H +#ifndef CONTAINUR_UTIL_H_ #define CONTAINER_UTIL_H_ // ----------------------------------- @@ -102,7 +102,8 @@ void print_map(const T & cont, std::ostream & out) { template unsigned find_index(const It & begin, const It & end, const V & val) { - for (unsigned idx = 0, It it = begin; it != end; it++, idx++) { + It it = begin; + for (unsigned idx = 0; it != end; it++, idx++) { if (*it == val) { return idx; } From 8acc924c21ee1eb65a14554636702bcad3170e81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 24 Oct 2017 16:34:49 -0700 Subject: [PATCH 30/57] ifndef/define match Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/fpa_rewriter.cpp | 1 - src/util/container_util.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index ce14349b2..e62c9346f 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -119,7 +119,6 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const // BV -> float SASSERT(bvs1 == sbits + ebits); unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); - unsynch_mpq_manager & mpqm = m_fm.mpq_manager(); scoped_mpz sig(mpzm), exp(mpzm); const mpz & sm1 = m_fm.m_powers2(sbits - 1); diff --git a/src/util/container_util.h b/src/util/container_util.h index f921b7b1d..e114c87b9 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -19,7 +19,7 @@ Revision History: --*/ -#ifndef CONTAINUR_UTIL_H_ +#ifndef CONTAINER_UTIL_H_ #define CONTAINER_UTIL_H_ // ----------------------------------- From 371f0b193c156e3221f41885a3c6ea0bfe26baeb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 02:59:04 -0700 Subject: [PATCH 31/57] move min_cut, fix #1321 Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/CMakeLists.txt | 1 - src/muz/spacer/spacer_min_cut.cpp | 289 -------------------- src/muz/spacer/spacer_min_cut.h | 53 ---- src/muz/spacer/spacer_unsat_core_plugin.cpp | 8 +- src/muz/spacer/spacer_unsat_core_plugin.h | 4 +- src/smt/theory_str.cpp | 72 ++--- src/util/CMakeLists.txt | 1 + src/util/min_cut.cpp | 229 ++++++++++++++++ src/util/min_cut.h | 56 ++++ 9 files changed, 328 insertions(+), 385 deletions(-) delete mode 100644 src/muz/spacer/spacer_min_cut.cpp delete mode 100644 src/muz/spacer/spacer_min_cut.h create mode 100644 src/util/min_cut.cpp create mode 100644 src/util/min_cut.h diff --git a/src/muz/spacer/CMakeLists.txt b/src/muz/spacer/CMakeLists.txt index 97c991e2a..37bc7f352 100644 --- a/src/muz/spacer/CMakeLists.txt +++ b/src/muz/spacer/CMakeLists.txt @@ -17,7 +17,6 @@ z3_add_component(spacer spacer_unsat_core_learner.cpp spacer_unsat_core_plugin.cpp spacer_matrix.cpp - spacer_min_cut.cpp spacer_antiunify.cpp spacer_mev_array.cpp spacer_qe_project.cpp diff --git a/src/muz/spacer/spacer_min_cut.cpp b/src/muz/spacer/spacer_min_cut.cpp deleted file mode 100644 index 22ff81a80..000000000 --- a/src/muz/spacer/spacer_min_cut.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/*++ -Copyright (c) 2017 Arie Gurfinkel - -Module Name: - - spacer_min_cut.cpp - -Abstract: - min cut solver - -Author: - Bernhard Gleiss - -Revision History: - - ---*/ -#include "muz/spacer/spacer_min_cut.h" - -namespace spacer { - - spacer_min_cut::spacer_min_cut() - { - m_n = 2; - - // push back two empty vectors for source and sink - m_edges.push_back(vector>()); - m_edges.push_back(vector>()); - } - - unsigned spacer_min_cut::new_node() - { - return m_n++; - } - - void spacer_min_cut::add_edge(unsigned int i, unsigned int j, unsigned int capacity) - { - if (i >= m_edges.size()) - { - m_edges.resize(i + 1); - } - m_edges[i].insert(std::make_pair(j, 1)); - STRACE("spacer.mincut", - verbose_stream() << "adding edge (" << i << "," << j << ")\n"; - ); - - } - - void spacer_min_cut::compute_min_cut(vector& cut_nodes) - { - if (m_n == 2) - { - return; - } - - m_d.resize(m_n); - m_pred.resize(m_n); - - // compute initial distances and number of nodes - compute_initial_distances(); - - unsigned i = 0; - - while (m_d[0] < m_n) - { - unsigned j = get_admissible_edge(i); - - if (j < m_n) - { - // advance(i) - m_pred[j] = i; - i = j; - - // if i is the sink, augment path - if (i == 1) - { - augment_path(); - i = 0; - } - } - else - { - // retreat - compute_distance(i); - if (i != 0) - { - i = m_pred[i]; - } - } - } - - // split nodes into reachable and unreachable ones - vector reachable(m_n); - compute_reachable_nodes(reachable); - - // find all edges between reachable and unreachable nodes and for each such edge, add corresponding lemma to unsat-core - compute_cut_and_add_lemmas(reachable, cut_nodes); - } - - void spacer_min_cut::compute_initial_distances() - { - vector todo; - vector visited(m_n); - - todo.push_back(0); // start at the source, since we do postorder traversel - - while (!todo.empty()) - { - unsigned current = todo.back(); - - // if we haven't already visited current - if (!visited[current]) { - bool existsUnvisitedParent = false; - - // add unprocessed parents to stack for DFS. If there is at least one unprocessed parent, don't compute the result - // for current now, but wait until those unprocessed parents are processed. - for (unsigned i = 0, sz = m_edges[current].size(); i < sz; ++i) - { - unsigned parent = m_edges[current][i].first; - - // if we haven't visited the current parent yet - if(!visited[parent]) - { - // add it to the stack - todo.push_back(parent); - existsUnvisitedParent = true; - } - } - - // if we already visited all parents, we can visit current too - if (!existsUnvisitedParent) { - visited[current] = true; - todo.pop_back(); - - compute_distance(current); // I.H. all parent distances are already computed - } - } - else { - todo.pop_back(); - } - } - } - - unsigned spacer_min_cut::get_admissible_edge(unsigned i) - { - for (const auto& pair : m_edges[i]) - { - if (pair.second > 0 && m_d[i] == m_d[pair.first] + 1) - { - return pair.first; - } - } - return m_n; // no element found - } - - void spacer_min_cut::augment_path() - { - // find bottleneck capacity - unsigned max = std::numeric_limits::max(); - unsigned k = 1; - while (k != 0) - { - unsigned l = m_pred[k]; - for (const auto& pair : m_edges[l]) - { - if (pair.first == k) - { - if (max > pair.second) - { - max = pair.second; - } - } - } - k = l; - } - - k = 1; - while (k != 0) - { - unsigned l = m_pred[k]; - - // decrease capacity - for (auto& pair : m_edges[l]) - { - if (pair.first == k) - { - pair.second -= max; - } - } - // increase reverse flow - bool already_exists = false; - for (auto& pair : m_edges[k]) - { - if (pair.first == l) - { - already_exists = true; - pair.second += max; - } - } - if (!already_exists) - { - m_edges[k].insert(std::make_pair(l, max)); - } - k = l; - } - } - - void spacer_min_cut::compute_distance(unsigned i) - { - if (i == 1) // sink node - { - m_d[1] = 0; - } - else - { - unsigned min = std::numeric_limits::max(); - - // find edge (i,j) with positive residual capacity and smallest distance - for (const auto& pair : m_edges[i]) - { - if (pair.second > 0) - { - unsigned tmp = m_d[pair.first] + 1; - if (tmp < min) - { - min = tmp; - } - } - } - m_d[i] = min; - } - } - - void spacer_min_cut::compute_reachable_nodes(vector& reachable) - { - vector todo; - - todo.push_back(0); - while (!todo.empty()) - { - unsigned current = todo.back(); - todo.pop_back(); - - if (!reachable[current]) - { - reachable[current] = true; - - for (const auto& pair : m_edges[current]) - { - if (pair.second > 0) - { - todo.push_back(pair.first); - } - } - } - } - } - - void spacer_min_cut::compute_cut_and_add_lemmas(vector& reachable, vector& cut_nodes) - { - vector todo; - vector visited(m_n); - - todo.push_back(0); - while (!todo.empty()) - { - unsigned current = todo.back(); - todo.pop_back(); - - if (!visited[current]) - { - visited[current] = true; - - for (const auto& pair : m_edges[current]) - { - unsigned successor = pair.first; - if (reachable[successor]) - { - todo.push_back(successor); - } - else - { - cut_nodes.push_back(successor); - } - } - } - } - } -} diff --git a/src/muz/spacer/spacer_min_cut.h b/src/muz/spacer/spacer_min_cut.h deleted file mode 100644 index c73a8d3d3..000000000 --- a/src/muz/spacer/spacer_min_cut.h +++ /dev/null @@ -1,53 +0,0 @@ -/*++ -Copyright (c) 2017 Arie Gurfinkel - -Module Name: - - spacer_min_cut.h - -Abstract: - min cut solver - -Author: - Bernhard Gleiss - -Revision History: - - ---*/ - -#ifndef _SPACER_MIN_CUT_H_ -#define _SPACER_MIN_CUT_H_ - -#include "ast/ast.h" -#include "util/vector.h" - -namespace spacer { - - class spacer_min_cut { - public: - spacer_min_cut(); - - unsigned new_node(); - void add_edge(unsigned i, unsigned j, unsigned capacity); - void compute_min_cut(vector& cut_nodes); - - private: - - unsigned m_n; // number of vertices in the graph - - vector > > m_edges; // map from node to all outgoing edges together with their weights (also contains "reverse edges") - vector m_d; // approximation of distance from node to sink in residual graph - vector m_pred; // predecessor-information for reconstruction of augmenting path - vector m_node_to_formula; // maps each node to the corresponding formula in the original proof - - void compute_initial_distances(); - unsigned get_admissible_edge(unsigned i); - void augment_path(); - void compute_distance(unsigned i); - void compute_reachable_nodes(vector& reachable); - void compute_cut_and_add_lemmas(vector& reachable, vector& cut_nodes); - }; -} - -#endif diff --git a/src/muz/spacer/spacer_unsat_core_plugin.cpp b/src/muz/spacer/spacer_unsat_core_plugin.cpp index 3f1e53778..af9230713 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.cpp +++ b/src/muz/spacer/spacer_unsat_core_plugin.cpp @@ -735,7 +735,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector cut_nodes; + unsigned_vector cut_nodes; m_min_cut.compute_min_cut(cut_nodes); for (unsigned cut_node : cut_nodes) diff --git a/src/muz/spacer/spacer_unsat_core_plugin.h b/src/muz/spacer/spacer_unsat_core_plugin.h index 743d7af4a..96d03140c 100644 --- a/src/muz/spacer/spacer_unsat_core_plugin.h +++ b/src/muz/spacer/spacer_unsat_core_plugin.h @@ -19,7 +19,7 @@ Revision History: #define _SPACER_UNSAT_CORE_PLUGIN_H_ #include "ast/ast.h" -#include "muz/spacer/spacer_min_cut.h" +#include "util/min_cut.h" namespace spacer { @@ -109,7 +109,7 @@ private: vector m_node_to_formula; // maps each node to the corresponding formula in the original proof - spacer_min_cut m_min_cut; + min_cut m_min_cut; }; } #endif diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 7e5685f9c..fc8122800 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -190,13 +190,13 @@ namespace smt { expr * theory_str::rewrite_implication(expr * premise, expr * conclusion) { ast_manager & m = get_manager(); - return m.mk_or(m.mk_not(premise), conclusion); + return m.mk_or(mk_not(m, premise), conclusion); } void theory_str::assert_implication(expr * premise, expr * conclusion) { ast_manager & m = get_manager(); TRACE("str", tout << "asserting implication " << mk_ismt2_pp(premise, m) << " -> " << mk_ismt2_pp(conclusion, m) << std::endl;); - expr_ref axiom(m.mk_or(m.mk_not(premise), conclusion), m); + expr_ref axiom(m.mk_or(mk_not(m, premise), conclusion), m); assert_axiom(axiom); } @@ -545,7 +545,7 @@ namespace smt { context & ctx = get_context(); ast_manager & m = get_manager(); - expr_ref ax1(m.mk_not(ctx.mk_eq_atom(s, mk_string(""))), m); + expr_ref ax1(mk_not(m, ctx.mk_eq_atom(s, mk_string(""))), m); assert_axiom(ax1); { @@ -557,7 +557,7 @@ namespace smt { SASSERT(zero); // build LHS > RHS and assert // we have to build !(LHS <= RHS) instead - expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); + expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m); SASSERT(lhs_gt_rhs); assert_axiom(lhs_gt_rhs); } @@ -592,7 +592,7 @@ namespace smt { SASSERT(zero); // build LHS > RHS and assert // we have to build !(LHS <= RHS) instead - expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); + expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m); SASSERT(lhs_gt_rhs); assert_axiom(lhs_gt_rhs); } @@ -1089,7 +1089,7 @@ namespace smt { m_autil.mk_ge(expr->get_arg(1), mk_int(0)), // REWRITE for arithmetic theory: // m_autil.mk_lt(expr->get_arg(1), mk_strlen(expr->get_arg(0))) - m.mk_not(m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0))) + mk_not(m, m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0))) ), m); expr_ref_vector and_item(m); @@ -1130,7 +1130,7 @@ namespace smt { expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts0), mk_strlen(expr->get_arg(0)))); - innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, m.mk_not(expr))); + innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, mk_not(m, expr))); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); SASSERT(then1); @@ -1143,7 +1143,7 @@ namespace smt { , m); SASSERT(topLevelCond); - expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); + expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); } @@ -1167,7 +1167,7 @@ namespace smt { expr_ref_vector innerItems(m); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts1), mk_strlen(expr->get_arg(0)))); - innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, m.mk_not(expr))); + innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, mk_not(m, expr))); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); SASSERT(then1); @@ -1180,7 +1180,7 @@ namespace smt { , m); SASSERT(topLevelCond); - expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); + expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m); SASSERT(finalAxiom); assert_axiom(finalAxiom); } @@ -1204,7 +1204,7 @@ namespace smt { if (haystackStr.contains(needleStr)) { assert_axiom(ex); } else { - assert_axiom(m.mk_not(ex)); + assert_axiom(mk_not(m, ex)); } return; } @@ -1265,7 +1265,7 @@ namespace smt { SASSERT(tmpLen); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m); SASSERT(thenBranch); @@ -1341,7 +1341,7 @@ namespace smt { expr_ref ite1(m.mk_ite( //m_autil.mk_lt(expr->get_arg(2), zeroAst), - m.mk_not(m_autil.mk_ge(expr->get_arg(2), zeroAst)), + mk_not(m, m_autil.mk_ge(expr->get_arg(2), zeroAst)), ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))), ite2 ), m); @@ -1384,7 +1384,7 @@ namespace smt { thenItems.push_back(m_autil.mk_ge(indexAst, mk_int(0))); // args[0] = x1 . args[1] . x2 // x1 doesn't contain args[1] - thenItems.push_back(m.mk_not(mk_contains(x2, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x2, expr->get_arg(1)))); thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1))); bool canSkip = false; @@ -1402,7 +1402,7 @@ namespace smt { expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x4, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x4, expr->get_arg(1)))); } //---------------------------- // else branch @@ -1452,7 +1452,7 @@ namespace smt { argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero)); // pos < strlen(base) // --> pos + -1*strlen(base) < 0 - argumentsValid_terms.push_back(m.mk_not(m_autil.mk_ge( + argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge( m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), zero))); @@ -1473,7 +1473,7 @@ namespace smt { // Case 1: pos < 0 or pos >= strlen(base) or len < 0 // ==> (Substr ...) = "" - expr_ref case1_premise(m.mk_not(argumentsValid), m); + expr_ref case1_premise(mk_not(m, argumentsValid), m); SASSERT(case1_premise); ctx.internalize(case1_premise, false); expr_ref case1_conclusion(ctx.mk_eq_atom(expr, mk_string("")), m); @@ -1505,7 +1505,7 @@ namespace smt { case3_conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(t3), substrLen)); case3_conclusion_terms.push_back(ctx.mk_eq_atom(expr, t3)); expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m); - expr_ref case3(rewrite_implication(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); + expr_ref case3(rewrite_implication(m.mk_and(argumentsValid, mk_not(m, lenOutOfBounds)), case3_conclusion), m); SASSERT(case3); ctx.internalize(case1, false); @@ -1548,7 +1548,7 @@ namespace smt { argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero)); // pos < strlen(base) // --> pos + -1*strlen(base) < 0 - argumentsValid_terms.push_back(m.mk_not(m_autil.mk_ge( + argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge( m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), zero))); // len >= 0 @@ -1564,7 +1564,7 @@ namespace smt { // Case 1: pos < 0 or pos >= strlen(base) or len < 0 // ==> (Substr ...) = "" - expr_ref case1_premise(m.mk_not(argumentsValid), m); + expr_ref case1_premise(mk_not(m, argumentsValid), m); expr_ref case1_conclusion(ctx.mk_eq_atom(expr, mk_string("")), m); expr_ref case1(m.mk_implies(case1_premise, case1_conclusion), m); @@ -1589,7 +1589,7 @@ namespace smt { case3_conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(t3), substrLen)); case3_conclusion_terms.push_back(ctx.mk_eq_atom(expr, t3)); expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m); - expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); + expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, mk_not(m, lenOutOfBounds)), case3_conclusion), m); assert_axiom(case1); assert_axiom(case2); @@ -1630,7 +1630,7 @@ namespace smt { expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(expr->get_arg(1)), mk_int(-1)), m); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); - thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); + thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1)))); thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(expr->get_arg(2), x2)))); // ----------------------- // false branch @@ -1684,7 +1684,7 @@ namespace smt { expr_ref tl(mk_str_var("tl"), m); expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m); expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m); - expr_ref conclusion3(m.mk_not(ctx.mk_eq_atom(hd, mk_string("0"))), m); + expr_ref conclusion3(mk_not(m, ctx.mk_eq_atom(hd, mk_string("0"))), m); expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m); SASSERT(premise); SASSERT(conclusion); @@ -1708,7 +1708,7 @@ namespace smt { // axiom 1: N < 0 <==> (str.from-int N) = "" expr * N = ex->get_arg(0); { - expr_ref axiom1_lhs(m.mk_not(m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m); + expr_ref axiom1_lhs(mk_not(m, m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m); expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, mk_string("")), m); expr_ref axiom1(ctx.mk_eq_atom(axiom1_lhs, axiom1_rhs), m); SASSERT(axiom1); @@ -1947,7 +1947,7 @@ namespace smt { // inconsistency check: value if (!can_two_nodes_eq(eqc_nn1, eqc_nn2)) { TRACE("str", tout << "inconsistency detected: " << mk_pp(eqc_nn1, m) << " cannot be equal to " << mk_pp(eqc_nn2, m) << std::endl;); - expr_ref to_assert(m.mk_not(ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m); + expr_ref to_assert(mk_not(m, ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m); assert_axiom(to_assert); // this shouldn't use the integer theory at all, so we don't allow the option of quick-return return false; @@ -2160,7 +2160,7 @@ namespace smt { expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg1), mk_int(makeUpLenArg1)), m); assert_implication(implyL11, implyR11); } else { - expr_ref neg(m.mk_not(implyL11), m); + expr_ref neg(mk_not(m, implyL11), m); assert_axiom(neg); } } @@ -2231,7 +2231,7 @@ namespace smt { expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg0), mk_int(makeUpLenArg0)), m); assert_implication(implyL11, implyR11); } else { - expr_ref neg(m.mk_not(implyL11), m); + expr_ref neg(mk_not(m, implyL11), m); assert_axiom(neg); } } @@ -2762,7 +2762,7 @@ namespace smt { } if (!can_two_nodes_eq(new_nn1, new_nn2)) { - expr_ref detected(m.mk_not(ctx.mk_eq_atom(new_nn1, new_nn2)), m); + expr_ref detected(mk_not(m, ctx.mk_eq_atom(new_nn1, new_nn2)), m); TRACE("str", tout << "inconsistency detected: " << mk_ismt2_pp(detected, m) << std::endl;); assert_axiom(detected); return; @@ -5008,7 +5008,7 @@ namespace smt { implyR = boolVar; } else { //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); } } else { // ------------------------------------------------------------------------------------------------ @@ -5037,7 +5037,7 @@ namespace smt { litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); } //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); break; } } @@ -5076,7 +5076,7 @@ namespace smt { implyR = boolVar; } else { // implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); - implyR = m.mk_not(boolVar); + implyR = mk_not(m, boolVar); } } @@ -5146,7 +5146,7 @@ namespace smt { litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); } expr_ref implyLHS(mk_and(litems), m); - expr_ref implyR(m.mk_not(boolVar), m); + expr_ref implyR(mk_not(m, boolVar), m); assert_implication(implyLHS, implyR); break; } @@ -6515,7 +6515,7 @@ namespace smt { if (matchRes) { assert_implication(implyL, boolVar); } else { - assert_implication(implyL, m.mk_not(boolVar)); + assert_implication(implyL, mk_not(m, boolVar)); } } } @@ -6603,7 +6603,7 @@ namespace smt { << arg1_str << "\" + \"" << arg2_str << "\" != \"" << const_str << "\"" << "\n";); expr_ref equality(ctx.mk_eq_atom(concat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } @@ -6621,7 +6621,7 @@ namespace smt { "\" is longer than \"" << const_str << "\"," << " so cannot be concatenated with anything to form it" << "\n";); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } else { @@ -6635,7 +6635,7 @@ namespace smt { << "actually \"" << arg2_str << "\"" << "\n";); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); - expr_ref diseq(m.mk_not(equality), m); + expr_ref diseq(mk_not(m, equality), m); assert_axiom(diseq); return; } else { diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 7ed68c89f..85b6f955c 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -28,6 +28,7 @@ z3_add_component(util lbool.cpp luby.cpp memory_manager.cpp + min_cut.cpp mpbq.cpp mpf.cpp mpff.cpp diff --git a/src/util/min_cut.cpp b/src/util/min_cut.cpp new file mode 100644 index 000000000..a56c5f6a0 --- /dev/null +++ b/src/util/min_cut.cpp @@ -0,0 +1,229 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + min_cut.cpp + +Abstract: + min cut solver + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ +#include "util/min_cut.h" + +min_cut::min_cut() { + // push back two empty vectors for source and sink + m_edges.push_back(edge_vector()); + m_edges.push_back(edge_vector()); +} + +unsigned min_cut::new_node() { + m_edges.push_back(edge_vector()); + return m_edges.size() - 1; +} + +void min_cut::add_edge(unsigned int i, unsigned int j) { + m_edges.reserve(i + 1); + m_edges[i].push_back(edge(j, 1)); + TRACE("spacer.mincut", tout << "adding edge (" << i << "," << j << ")\n";); +} + +void min_cut::compute_min_cut(unsigned_vector& cut_nodes) { + if (m_edges.size() == 2) { + return; + } + + m_d.resize(m_edges.size()); + m_pred.resize(m_edges.size()); + + // compute initial distances and number of nodes + compute_initial_distances(); + + unsigned i = 0; + + while (m_d[0] < m_edges.size()) { + unsigned j = get_admissible_edge(i); + + if (j < m_edges.size()) { + // advance(i) + m_pred[j] = i; + i = j; + + // if i is the sink, augment path + if (i == 1) { + augment_path(); + i = 0; + } + } + else { + // retreat + compute_distance(i); + if (i != 0) { + i = m_pred[i]; + } + } + } + + // split nodes into reachable and unreachable ones + bool_vector reachable(m_edges.size()); + compute_reachable_nodes(reachable); + + // find all edges between reachable and unreachable nodes and for each such edge, add corresponding lemma to unsat-core + compute_cut_and_add_lemmas(reachable, cut_nodes); +} + +void min_cut::compute_initial_distances() { + unsigned_vector todo; + bool_vector visited(m_edges.size()); + + todo.push_back(0); // start at the source, since we do postorder traversel + + while (!todo.empty()) { + unsigned current = todo.back(); + + // if we haven't already visited current + if (!visited[current]) { + bool exists_unvisited_parent = false; + + // add unprocessed parents to stack for DFS. If there is at least one unprocessed parent, don't compute the result + // for current now, but wait until those unprocessed parents are processed + for (auto const& edge : m_edges[current]) { + unsigned parent = edge.node; + + // if we haven't visited the current parent yet + if (!visited[parent]) { + // add it to the stack + todo.push_back(parent); + exists_unvisited_parent = true; + } + } + + // if we already visited all parents, we can visit current too + if (!exists_unvisited_parent) { + visited[current] = true; + todo.pop_back(); + + compute_distance(current); // I.H. all parent distances are already computed + } + } + else { + todo.pop_back(); + } + } +} + +unsigned min_cut::get_admissible_edge(unsigned i) { + for (const auto& edge : m_edges[i]) { + if (edge.weight > 0 && m_d[i] == m_d[edge.node] + 1) { + return edge.node; + } + } + return m_edges.size(); // no element found +} + +void min_cut::augment_path() { + // find bottleneck capacity + unsigned max = std::numeric_limits::max(); + unsigned k = 1; + while (k != 0) { + unsigned l = m_pred[k]; + for (const auto& edge : m_edges[l]) { + if (edge.node == k) { + max = std::min(max, edge.weight); + } + } + k = l; + } + + k = 1; + while (k != 0) { + unsigned l = m_pred[k]; + + // decrease capacity + for (auto& edge : m_edges[l]) { + if (edge.node == k) { + edge.weight -= max; + } + } + // increase reverse flow + bool already_exists = false; + for (auto& edge : m_edges[k]) { + if (edge.node == l) { + already_exists = true; + edge.weight += max; + } + } + if (!already_exists) { + m_edges[k].push_back(edge(1, max)); + } + k = l; + } +} + +void min_cut::compute_distance(unsigned i) { + if (i == 1) { // sink node + m_d[1] = 0; + } + else { + unsigned min = std::numeric_limits::max(); + + // find edge (i,j) with positive residual capacity and smallest distance + for (const auto& edge : m_edges[i]) { + if (edge.weight > 0) { + min = std::min(min, m_d[edge.node] + 1); + } + } + m_d[i] = min; + } +} + +void min_cut::compute_reachable_nodes(bool_vector& reachable) { + unsigned_vector todo; + + todo.push_back(0); + while (!todo.empty()) { + unsigned current = todo.back(); + todo.pop_back(); + + if (!reachable[current]) { + reachable[current] = true; + + for (const auto& edge : m_edges[current]) { + if (edge.weight > 0) { + todo.push_back(edge.node); + } + } + } + } +} + +void min_cut::compute_cut_and_add_lemmas(bool_vector& reachable, unsigned_vector& cut_nodes) { + unsigned_vector todo; + bool_vector visited(m_edges.size()); + + todo.push_back(0); + while (!todo.empty()) { + unsigned current = todo.back(); + todo.pop_back(); + + if (!visited[current]) { + visited[current] = true; + + for (const auto& edge : m_edges[current]) { + unsigned successor = edge.node; + if (reachable[successor]) { + todo.push_back(successor); + } + else { + cut_nodes.push_back(successor); + } + } + } + } +} diff --git a/src/util/min_cut.h b/src/util/min_cut.h new file mode 100644 index 000000000..246377f1f --- /dev/null +++ b/src/util/min_cut.h @@ -0,0 +1,56 @@ +/*++ +Copyright (c) 2017 Arie Gurfinkel + +Module Name: + + min_cut.h + +Abstract: + min cut solver + +Author: + Bernhard Gleiss + +Revision History: + + +--*/ + +#ifndef MIN_CUT_H_ +#define MIN_CUT_H_ + +#include "ast/ast.h" +#include "util/vector.h" + + +class min_cut { +public: + min_cut(); + + unsigned new_node(); + /* + \brief add an edge (with unit capacity) + */ + void add_edge(unsigned i, unsigned j); + + void compute_min_cut(unsigned_vector& cut_nodes); + +private: + + typedef svector bool_vector; + struct edge { unsigned node; unsigned weight; edge(unsigned n, unsigned w): node(n), weight(w) {} edge(): node(0), weight(0) {} }; + typedef svector edge_vector; + + vector m_edges; // map from node to all outgoing edges together with their weights (also contains "reverse edges") + unsigned_vector m_d; // approximation of distance from node to sink in residual graph + unsigned_vector m_pred; // predecessor-information for reconstruction of augmenting path + + void compute_initial_distances(); + unsigned get_admissible_edge(unsigned i); + void augment_path(); + void compute_distance(unsigned i); + void compute_reachable_nodes(bool_vector& reachable); + void compute_cut_and_add_lemmas(bool_vector& reachable, unsigned_vector& cut_nodes); +}; + +#endif From de3700e1fd5fc8c005fd8048e3ef979e19b2ec2e Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Wed, 25 Oct 2017 11:13:25 +0100 Subject: [PATCH 32/57] [CMake] Try to unbreak the C example build with older GCC versions by forcing the language version to be C99. --- examples/c/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index bac08e460..c47a4947a 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -7,6 +7,19 @@ # the C++ standard library in resulting in a link failure. project(Z3_C_EXAMPLE C CXX) cmake_minimum_required(VERSION 2.8.12) + +# Set C version required to C99 +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR + ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 ") + endif() +else() + set(CMAKE_C_STANDARD_REQUIRED ON) + set(CMAKE_C_STANDARD 99) + set(CMAKE_C_EXTENSIONS OFF) +endif() + find_package(Z3 REQUIRED CONFIG From f5f1d019d81de5e93aa53237d31ecbfcd9dd06c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 09:00:35 -0700 Subject: [PATCH 33/57] missing files Signed-off-by: Nikolaj Bjorner --- src/util/min_cut.cpp | 4 ++-- src/util/min_cut.h | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/util/min_cut.cpp b/src/util/min_cut.cpp index a56c5f6a0..2f7bdb862 100644 --- a/src/util/min_cut.cpp +++ b/src/util/min_cut.cpp @@ -28,9 +28,9 @@ unsigned min_cut::new_node() { return m_edges.size() - 1; } -void min_cut::add_edge(unsigned int i, unsigned int j) { +void min_cut::add_edge(unsigned int i, unsigned int j, unsigned capacity) { m_edges.reserve(i + 1); - m_edges[i].push_back(edge(j, 1)); + m_edges[i].push_back(edge(j, capacity)); TRACE("spacer.mincut", tout << "adding edge (" << i << "," << j << ")\n";); } diff --git a/src/util/min_cut.h b/src/util/min_cut.h index 246377f1f..5a783a8d0 100644 --- a/src/util/min_cut.h +++ b/src/util/min_cut.h @@ -27,12 +27,20 @@ class min_cut { public: min_cut(); - unsigned new_node(); /* - \brief add an edge (with unit capacity) + \brief create a node */ - void add_edge(unsigned i, unsigned j); + unsigned new_node(); + /* + \brief add an i -> j edge with (unit) capacity + */ + void add_edge(unsigned i, unsigned j, unsigned capacity = 1); + + /* + \brief produce a min cut between source node = 0 and target node = 1. + NB. the function changes capacities on edges. + */ void compute_min_cut(unsigned_vector& cut_nodes); private: From 0268f2243ec8939f3e72db2761724418415818a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 09:49:53 -0700 Subject: [PATCH 34/57] remove ast.h reference Signed-off-by: Nikolaj Bjorner --- src/util/min_cut.cpp | 7 +++++-- src/util/min_cut.h | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/util/min_cut.cpp b/src/util/min_cut.cpp index 2f7bdb862..b7c30f546 100644 --- a/src/util/min_cut.cpp +++ b/src/util/min_cut.cpp @@ -16,6 +16,7 @@ Revision History: --*/ #include "util/min_cut.h" +#include "util/trace.h" min_cut::min_cut() { // push back two empty vectors for source and sink @@ -74,7 +75,8 @@ void min_cut::compute_min_cut(unsigned_vector& cut_nodes) { bool_vector reachable(m_edges.size()); compute_reachable_nodes(reachable); - // find all edges between reachable and unreachable nodes and for each such edge, add corresponding lemma to unsat-core + // find all edges between reachable and unreachable nodes and + // for each such edge, add corresponding lemma to unsat-core compute_cut_and_add_lemmas(reachable, cut_nodes); } @@ -91,7 +93,8 @@ void min_cut::compute_initial_distances() { if (!visited[current]) { bool exists_unvisited_parent = false; - // add unprocessed parents to stack for DFS. If there is at least one unprocessed parent, don't compute the result + // add unprocessed parents to stack for DFS. If there is at least + // one unprocessed parent, don't compute the result // for current now, but wait until those unprocessed parents are processed for (auto const& edge : m_edges[current]) { unsigned parent = edge.node; diff --git a/src/util/min_cut.h b/src/util/min_cut.h index 5a783a8d0..51a330126 100644 --- a/src/util/min_cut.h +++ b/src/util/min_cut.h @@ -19,7 +19,6 @@ Revision History: #ifndef MIN_CUT_H_ #define MIN_CUT_H_ -#include "ast/ast.h" #include "util/vector.h" From 2c2705628317698709c3113bf6c11acdebc02ec7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 10:24:49 -0700 Subject: [PATCH 35/57] disable model example pending C compliance or C99 or whatever adjustment Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 433c7ebcf..178b77b86 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2844,9 +2844,9 @@ void fpa_example() { \brief Demonstrates some basic features of model construction */ +#if 0 void mk_model_example() { printf("\nmk_model_example\n"); - LOG_MSG("mk_model_example"); Z3_context ctx = mk_context(); // Construct empty model Z3_model m = Z3_mk_model(ctx); @@ -2973,7 +2973,7 @@ void mk_model_example() { printf("a+b did not evaluate to expected value\n"); exit(1); } - + // Evaluate c[0] + c[1] + c[2] under model Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral); Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral); @@ -3009,6 +3009,7 @@ void mk_model_example() { Z3_model_dec_ref(ctx, m); Z3_del_context(ctx); } +#endif /*@}*/ /*@}*/ @@ -3058,6 +3059,6 @@ int main() { substitute_example(); substitute_vars_example(); fpa_example(); - mk_model_example(); +// mk_model_example(); return 0; } From 7ed32f43151816c734ddda6e56ced4e5e3b7834b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 10:48:53 -0700 Subject: [PATCH 36/57] re-add model example Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 367 ++++++++++++++++++++++------------------- 1 file changed, 194 insertions(+), 173 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 178b77b86..d9db91c66 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2769,73 +2769,73 @@ void fpa_example() { double_sort = Z3_mk_fpa_sort(ctx, 11, 53); rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); - // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). - s_rm = Z3_mk_string_symbol(ctx, "rm"); - rm = Z3_mk_const(ctx, s_rm, rm_sort); - s_x = Z3_mk_string_symbol(ctx, "x"); - s_y = Z3_mk_string_symbol(ctx, "y"); - x = Z3_mk_const(ctx, s_x, double_sort); - y = Z3_mk_const(ctx, s_y, double_sort); - n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); - - s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y"); - x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort); - c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y)); - - args[0] = c1; - args[1] = Z3_mk_eq(ctx, x_plus_y, n); - c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); - - args2[0] = c2; - args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))); - c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); - - and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)); - and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)); - and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)); - args3[0] = c3; - args3[1] = Z3_mk_and(ctx, 3, and_args); - c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); - - printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); - Z3_solver_push(ctx, s); - Z3_solver_assert(ctx, s, c4); - check(ctx, s, Z3_L_TRUE); - Z3_solver_pop(ctx, s, 1); - - // Show that the following are equal: - // (fp #b0 #b10000000001 #xc000000000000) - // ((_ to_fp 11 53) #x401c000000000000)) - // ((_ to_fp 11 53) RTZ 1.75 2))) - // ((_ to_fp 11 53) RTZ 7.0))) - - Z3_solver_push(ctx, s); - c1 = Z3_mk_fpa_fp(ctx, - Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)), - Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)), + // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). + s_rm = Z3_mk_string_symbol(ctx, "rm"); + rm = Z3_mk_const(ctx, s_rm, rm_sort); + s_x = Z3_mk_string_symbol(ctx, "x"); + s_y = Z3_mk_string_symbol(ctx, "y"); + x = Z3_mk_const(ctx, s_x, double_sort); + y = Z3_mk_const(ctx, s_y, double_sort); + n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); + + s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y"); + x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort); + c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y)); + + args[0] = c1; + args[1] = Z3_mk_eq(ctx, x_plus_y, n); + c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); + + args2[0] = c2; + args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))); + c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); + + and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)); + and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)); + and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)); + args3[0] = c3; + args3[1] = Z3_mk_and(ctx, 3, and_args); + c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); + + printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); + Z3_solver_push(ctx, s); + Z3_solver_assert(ctx, s, c4); + check(ctx, s, Z3_L_TRUE); + Z3_solver_pop(ctx, s, 1); + + // Show that the following are equal: + // (fp #b0 #b10000000001 #xc000000000000) + // ((_ to_fp 11 53) #x401c000000000000)) + // ((_ to_fp 11 53) RTZ 1.75 2))) + // ((_ to_fp 11 53) RTZ 7.0))) + + Z3_solver_push(ctx, s); + c1 = Z3_mk_fpa_fp(ctx, + Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)), + Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)), Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52))); - c2 = Z3_mk_fpa_to_fp_bv(ctx, - Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), - Z3_mk_fpa_sort(ctx, 11, 53)); + c2 = Z3_mk_fpa_to_fp_bv(ctx, + Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), + Z3_mk_fpa_sort(ctx, 11, 53)); c3 = Z3_mk_fpa_to_fp_int_real(ctx, Z3_mk_fpa_rtz(ctx), - Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ + Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), /* significand */ Z3_mk_fpa_sort(ctx, 11, 53)); c4 = Z3_mk_fpa_to_fp_real(ctx, - Z3_mk_fpa_rtz(ctx), - Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), - Z3_mk_fpa_sort(ctx, 11, 53)); - args3[0] = Z3_mk_eq(ctx, c1, c2); - args3[1] = Z3_mk_eq(ctx, c1, c3); - args3[2] = Z3_mk_eq(ctx, c1, c4); - c5 = Z3_mk_and(ctx, 3, args3); - - printf("c5: %s\n", Z3_ast_to_string(ctx, c5)); - Z3_solver_assert(ctx, s, c5); - check(ctx, s, Z3_L_TRUE); - Z3_solver_pop(ctx, s, 1); - + Z3_mk_fpa_rtz(ctx), + Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), + Z3_mk_fpa_sort(ctx, 11, 53)); + args3[0] = Z3_mk_eq(ctx, c1, c2); + args3[1] = Z3_mk_eq(ctx, c1, c3); + args3[2] = Z3_mk_eq(ctx, c1, c4); + c5 = Z3_mk_and(ctx, 3, args3); + + printf("c5: %s\n", Z3_ast_to_string(ctx, c5)); + Z3_solver_assert(ctx, s, c5); + check(ctx, s, Z3_L_TRUE); + Z3_solver_pop(ctx, s, 1); + del_solver(ctx, s); Z3_del_context(ctx); } @@ -2844,52 +2844,67 @@ void fpa_example() { \brief Demonstrates some basic features of model construction */ -#if 0 void mk_model_example() { + Z3_context ctx; + Z3_model m; + Z3_sort intSort; + Z3_symbol aSymbol, bSymbol, cSymbol; + Z3_func_decl aFuncDecl, bFuncDecl, cFuncDecl; + Z3_ast aApp, bApp, cApp; + Z3_sort int2intArraySort; + Z3_ast zeroNumeral, oneNumeral, twoNumeral, threeNumeral, fourNumeral; + Z3_sort arrayDomain[1]; + Z3_func_decl cAsFuncDecl; + Z3_func_interp cAsFuncInterp; + Z3_ast_vector zeroArgs; + Z3_ast_vector oneArgs; + Z3_ast cFuncDeclAsArray; + Z3_string modelAsString; + printf("\nmk_model_example\n"); - Z3_context ctx = mk_context(); + ctx = mk_context(); // Construct empty model - Z3_model m = Z3_mk_model(ctx); + m = Z3_mk_model(ctx); Z3_model_inc_ref(ctx, m); // Create constants "a" and "b" - Z3_sort intSort = Z3_mk_int_sort(ctx); - Z3_symbol aSymbol = Z3_mk_string_symbol(ctx, "a"); - Z3_func_decl aFuncDecl = Z3_mk_func_decl(ctx, aSymbol, - /*domain_size=*/0, - /*domain=*/NULL, - /*range=*/intSort); - Z3_ast aApp = Z3_mk_app(ctx, aFuncDecl, - /*num_args=*/0, - /*args=*/NULL); - Z3_symbol bSymbol = Z3_mk_string_symbol(ctx, "b"); - Z3_func_decl bFuncDecl = Z3_mk_func_decl(ctx, bSymbol, - /*domain_size=*/0, - /*domain=*/NULL, - /*range=*/intSort); - Z3_ast bApp = Z3_mk_app(ctx, bFuncDecl, - /*num_args=*/0, - /*args=*/NULL); + intSort = Z3_mk_int_sort(ctx); + aSymbol = Z3_mk_string_symbol(ctx, "a"); + aFuncDecl = Z3_mk_func_decl(ctx, aSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + aApp = Z3_mk_app(ctx, aFuncDecl, + /*num_args=*/0, + /*args=*/NULL); + bSymbol = Z3_mk_string_symbol(ctx, "b"); + bFuncDecl = Z3_mk_func_decl(ctx, bSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/intSort); + bApp = Z3_mk_app(ctx, bFuncDecl, + /*num_args=*/0, + /*args=*/NULL); // Create array "c" that maps int to int. - Z3_symbol cSymbol = Z3_mk_string_symbol(ctx, "c"); - Z3_sort int2intArraySort = Z3_mk_array_sort(ctx, - /*domain=*/intSort, - /*range=*/intSort); - Z3_func_decl cFuncDecl = Z3_mk_func_decl(ctx, cSymbol, - /*domain_size=*/0, - /*domain=*/NULL, - /*range=*/int2intArraySort); - Z3_ast cApp = Z3_mk_app(ctx, cFuncDecl, - /*num_args=*/0, - /*args=*/NULL); + cSymbol = Z3_mk_string_symbol(ctx, "c"); + int2intArraySort = Z3_mk_array_sort(ctx, + /*domain=*/intSort, + /*range=*/intSort); + cFuncDecl = Z3_mk_func_decl(ctx, cSymbol, + /*domain_size=*/0, + /*domain=*/NULL, + /*range=*/int2intArraySort); + cApp = Z3_mk_app(ctx, cFuncDecl, + /*num_args=*/0, + /*args=*/NULL); // Create numerals to be used in model - Z3_ast zeroNumeral = Z3_mk_int(ctx, 0, intSort); - Z3_ast oneNumeral = Z3_mk_int(ctx, 1, intSort); - Z3_ast twoNumeral = Z3_mk_int(ctx, 2, intSort); - Z3_ast threeNumeral = Z3_mk_int(ctx, 3, intSort); - Z3_ast fourNumeral = Z3_mk_int(ctx, 4, intSort); + zeroNumeral = Z3_mk_int(ctx, 0, intSort); + oneNumeral = Z3_mk_int(ctx, 1, intSort); + twoNumeral = Z3_mk_int(ctx, 2, intSort); + threeNumeral = Z3_mk_int(ctx, 3, intSort); + fourNumeral = Z3_mk_int(ctx, 4, intSort); // Add assignments to model // a == 1 @@ -2899,25 +2914,25 @@ void mk_model_example() { // Create a fresh function that represents // reading from array. - Z3_sort arrayDomain[] = {intSort}; - Z3_func_decl cAsFuncDecl = Z3_mk_fresh_func_decl(ctx, - /*prefix=*/"", - /*domain_size*/ 1, - /*domain=*/arrayDomain, - /*sort=*/intSort); + arrayDomain[0] = intSort; + cAsFuncDecl = Z3_mk_fresh_func_decl(ctx, + /*prefix=*/"", + /*domain_size*/ 1, + /*domain=*/arrayDomain, + /*sort=*/intSort); // Create function interpretation with default // value of "0". - Z3_func_interp cAsFuncInterp = + cAsFuncInterp = Z3_add_func_interp(ctx, m, cAsFuncDecl, /*default_value=*/zeroNumeral); Z3_func_interp_inc_ref(ctx, cAsFuncInterp); // Add [0] = 3 - Z3_ast_vector zeroArgs = Z3_mk_ast_vector(ctx); + zeroArgs = Z3_mk_ast_vector(ctx); Z3_ast_vector_inc_ref(ctx, zeroArgs); Z3_ast_vector_push(ctx, zeroArgs, zeroNumeral); Z3_func_interp_add_entry(ctx, cAsFuncInterp, zeroArgs, threeNumeral); // Add [1] = 4 - Z3_ast_vector oneArgs = Z3_mk_ast_vector(ctx); + oneArgs = Z3_mk_ast_vector(ctx); Z3_ast_vector_inc_ref(ctx, oneArgs); Z3_ast_vector_push(ctx, oneArgs, oneNumeral); Z3_func_interp_add_entry(ctx, cAsFuncInterp, oneArgs, fourNumeral); @@ -2925,82 +2940,89 @@ void mk_model_example() { // Now use the `(_ as_array)` to associate // the `cAsFuncInterp` with the `cFuncDecl` // in the model - Z3_ast cFuncDeclAsArray = Z3_mk_as_array(ctx, cAsFuncDecl); + cFuncDeclAsArray = Z3_mk_as_array(ctx, cAsFuncDecl); Z3_add_const_interp(ctx, m, cFuncDecl, cFuncDeclAsArray); // Print the model - Z3_string modelAsString = Z3_model_to_string(ctx, m); + modelAsString = Z3_model_to_string(ctx, m); printf("Model:\n%s\n", modelAsString); // Check the interpretations we expect to be present // are. - Z3_func_decl expectedInterpretations[] = {aFuncDecl, bFuncDecl, cFuncDecl}; - for (int index = 0; - index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl); - ++index) { - Z3_func_decl d = expectedInterpretations[index]; - if (Z3_model_has_interp(ctx, m, d)) { - printf("Found interpretation for \"%s\"\n", - Z3_ast_to_string(ctx, Z3_func_decl_to_ast(ctx, d))); - } else { - printf("Missing interpretation"); + { + Z3_func_decl expectedInterpretations[] = {aFuncDecl, bFuncDecl, cFuncDecl}; + for (int index = 0; + index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl); + ++index) { + Z3_func_decl d = expectedInterpretations[index]; + if (Z3_model_has_interp(ctx, m, d)) { + printf("Found interpretation for \"%s\"\n", + Z3_ast_to_string(ctx, Z3_func_decl_to_ast(ctx, d))); + } else { + printf("Missing interpretation"); + exit(1); + } + } + } + + { + // Evaluate a + b under model + Z3_ast addArgs[] = {aApp, bApp}; + Z3_ast aPlusB = Z3_mk_add(ctx, + /*num_args=*/2, + /*args=*/addArgs); + Z3_ast aPlusBEval = NULL; + Z3_bool aPlusBEvalSuccess = + Z3_model_eval(ctx, m, aPlusB, + /*model_completion=*/Z3_FALSE, &aPlusBEval); + if (aPlusBEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + + int aPlusBValue = 0; + Z3_bool getAPlusBValueSuccess = + Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); + if (getAPlusBValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for a+b\n"); + exit(1); + } + printf("Evaluated a + b = %d\n", aPlusBValue); + if (aPlusBValue != 3) { + printf("a+b did not evaluate to expected value\n"); exit(1); } } - // Evaluate a + b under model - Z3_ast addArgs[] = {aApp, bApp}; - Z3_ast aPlusB = Z3_mk_add(ctx, - /*num_args=*/2, - /*args=*/addArgs); - Z3_ast aPlusBEval = NULL; - Z3_bool aPlusBEvalSuccess = - Z3_model_eval(ctx, m, aPlusB, - /*model_completion=*/Z3_FALSE, &aPlusBEval); - if (aPlusBEvalSuccess != Z3_TRUE) { - printf("Failed to evaluate model\n"); - exit(1); - } - int aPlusBValue = 0; - Z3_bool getAPlusBValueSuccess = - Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); - if (getAPlusBValueSuccess != Z3_TRUE) { - printf("Failed to get integer value for a+b\n"); - exit(1); - } - printf("Evaluated a + b = %d\n", aPlusBValue); - if (aPlusBValue != 3) { - printf("a+b did not evaluate to expected value\n"); - exit(1); - } - - // Evaluate c[0] + c[1] + c[2] under model - Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral); - Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral); - Z3_ast c2 = Z3_mk_select(ctx, cApp, twoNumeral); - Z3_ast arrayAddArgs[] = {c0, c1, c2}; - Z3_ast arrayAdd = Z3_mk_add(ctx, - /*num_args=*/3, - /*args=*/arrayAddArgs); - Z3_ast arrayAddEval = NULL; - Z3_bool arrayAddEvalSuccess = - Z3_model_eval(ctx, m, arrayAdd, - /*model_completion=*/Z3_FALSE, &arrayAddEval); - if (arrayAddEvalSuccess != Z3_TRUE) { - printf("Failed to evaluate model\n"); - exit(1); - } - int arrayAddValue = 0; - Z3_bool getArrayAddValueSuccess = - Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); - if (getArrayAddValueSuccess != Z3_TRUE) { - printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); - exit(1); - } - printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); - if (arrayAddValue != 7) { - printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); - exit(1); + { + // Evaluate c[0] + c[1] + c[2] under model + Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral); + Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral); + Z3_ast c2 = Z3_mk_select(ctx, cApp, twoNumeral); + Z3_ast arrayAddArgs[] = {c0, c1, c2}; + Z3_ast arrayAdd = Z3_mk_add(ctx, + /*num_args=*/3, + /*args=*/arrayAddArgs); + Z3_ast arrayAddEval = NULL; + Z3_bool arrayAddEvalSuccess = + Z3_model_eval(ctx, m, arrayAdd, + /*model_completion=*/Z3_FALSE, &arrayAddEval); + if (arrayAddEvalSuccess != Z3_TRUE) { + printf("Failed to evaluate model\n"); + exit(1); + } + int arrayAddValue = 0; + Z3_bool getArrayAddValueSuccess = + Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); + if (getArrayAddValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); + exit(1); + } + printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); + if (arrayAddValue != 7) { + printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); + exit(1); + } } Z3_ast_vector_dec_ref(ctx, oneArgs); @@ -3009,7 +3031,6 @@ void mk_model_example() { Z3_model_dec_ref(ctx, m); Z3_del_context(ctx); } -#endif /*@}*/ /*@}*/ @@ -3059,6 +3080,6 @@ int main() { substitute_example(); substitute_vars_example(); fpa_example(); -// mk_model_example(); + mk_model_example(); return 0; } From fc73271b83c7ac0d0f55249363a07cc7f15da48e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 11:20:56 -0700 Subject: [PATCH 37/57] more C fixes to model example Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 53 +++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index d9db91c66..f6d515389 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2950,8 +2950,9 @@ void mk_model_example() { // Check the interpretations we expect to be present // are. { - Z3_func_decl expectedInterpretations[] = {aFuncDecl, bFuncDecl, cFuncDecl}; - for (int index = 0; + Z3_func_decl expectedInterpretations[3] = {aFuncDecl, bFuncDecl, cFuncDecl}; + int index; + for (index = 0; index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl); ++index) { Z3_func_decl d = expectedInterpretations[index]; @@ -2980,17 +2981,19 @@ void mk_model_example() { exit(1); } - int aPlusBValue = 0; - Z3_bool getAPlusBValueSuccess = - Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); - if (getAPlusBValueSuccess != Z3_TRUE) { - printf("Failed to get integer value for a+b\n"); - exit(1); - } - printf("Evaluated a + b = %d\n", aPlusBValue); - if (aPlusBValue != 3) { - printf("a+b did not evaluate to expected value\n"); - exit(1); + { + int aPlusBValue = 0; + Z3_bool getAPlusBValueSuccess = + Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue); + if (getAPlusBValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for a+b\n"); + exit(1); + } + printf("Evaluated a + b = %d\n", aPlusBValue); + if (aPlusBValue != 3) { + printf("a+b did not evaluate to expected value\n"); + exit(1); + } } } @@ -3011,17 +3014,19 @@ void mk_model_example() { printf("Failed to evaluate model\n"); exit(1); } - int arrayAddValue = 0; - Z3_bool getArrayAddValueSuccess = - Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); - if (getArrayAddValueSuccess != Z3_TRUE) { - printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); - exit(1); - } - printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); - if (arrayAddValue != 7) { - printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); - exit(1); + { + int arrayAddValue = 0; + Z3_bool getArrayAddValueSuccess = + Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue); + if (getArrayAddValueSuccess != Z3_TRUE) { + printf("Failed to get integer value for c[0] + c[1] + c[2]\n"); + exit(1); + } + printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue); + if (arrayAddValue != 7) { + printf("c[0] + c[1] + c[2] did not evaluate to expected value\n"); + exit(1); + } } } From 0589a20b46b0edd486dbc0b4d7113d2b048598ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 19:24:45 -0700 Subject: [PATCH 38/57] fix #1326 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 14 ++++++++------ src/opt/opt_context.cpp | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index e708788f6..3707e5aeb 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -229,6 +229,7 @@ public: } lbool primal_dual_solver() { + std::cout << "pd\n"; if (!init()) return l_undef; lbool is_sat = init_local(); trace(); @@ -315,14 +316,13 @@ public: void found_optimum() { IF_VERBOSE(1, verbose_stream() << "found optimum\n";); - rational upper(0); + m_lower.reset(); for (unsigned i = 0; i < m_soft.size(); ++i) { m_assignment[i] = is_true(m_soft[i]); if (!m_assignment[i]) { - upper += m_weights[i]; + m_lower += m_weights[i]; } } - SASSERT(upper == m_lower); m_upper = m_lower; m_found_feasible_optimum = true; } @@ -397,10 +397,11 @@ public: void get_current_correction_set(model* mdl, exprs& cs) { cs.reset(); if (!mdl) return; - for (unsigned i = 0; i < m_asms.size(); ++i) { - if (is_false(mdl, m_asms[i].get())) { - cs.push_back(m_asms[i].get()); + for (expr* a : m_asms) { + if (is_false(mdl, a)) { + cs.push_back(a); } + TRACE("opt", expr_ref tmp(m); mdl->eval(a, tmp, true); tout << mk_pp(a, m) << ": " << tmp << "\n";); } TRACE("opt", display_vec(tout << "new correction set: ", cs);); } @@ -509,6 +510,7 @@ public: trace(); if (m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) { exprs cs; + TRACE("opt", tout << "cs " << m_correction_set_size << " " << core.size() << "\n";); get_current_correction_set(m_csmodel.get(), cs); m_correction_set_size = cs.size(); if (m_correction_set_size < core.size()) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 2b31e243c..8d73ea7c8 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -819,7 +819,7 @@ namespace opt { bool is_max = is_maximize(fml, term, orig_term, index); bool is_min = !is_max && is_minimize(fml, term, orig_term, index); if (is_min && get_pb_sum(term, terms, weights, offset)) { - TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); + TRACE("opt", tout << "try to convert minimization\n" << mk_pp(term, m) << "\n";); // minimize 2*x + 3*y // <=> // (assert-soft (not x) 2) From e7aa6455bce9ef77d6fcfcd1dcb2c31aa225e59c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 19:25:25 -0700 Subject: [PATCH 39/57] fix #1326 Signed-off-by: Nikolaj Bjorner --- src/opt/maxres.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index 3707e5aeb..b06773223 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -229,7 +229,6 @@ public: } lbool primal_dual_solver() { - std::cout << "pd\n"; if (!init()) return l_undef; lbool is_sat = init_local(); trace(); From c886b6d50033daa6a5a0c2ebe953dc56452d91cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 25 Oct 2017 20:53:10 -0700 Subject: [PATCH 40/57] fix #1330. Interpolation transformation needs to handle TRANSITIVITY_STAR Signed-off-by: Nikolaj Bjorner --- src/interp/iz3mgr.h | 24 ++++++++++++------------ src/interp/iz3translate.cpp | 17 +++++++++++++++++ src/interp/iz3translate.h | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index e4c294059..0ad751326 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -57,12 +57,12 @@ typedef ast raw_ast; /** Wrapper around an ast pointer */ class ast_i { - protected: +protected: raw_ast *_ast; - public: +public: raw_ast * const &raw() const {return _ast;} ast_i(raw_ast *a){_ast = a;} - + ast_i(){_ast = 0;} bool eq(const ast_i &other) const { return _ast == other._ast; @@ -86,19 +86,19 @@ class ast_i { /** Reference counting verison of above */ class ast_r : public ast_i { ast_manager *_m; - public: - ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { +public: + ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { _m = m; m->inc_ref(a); } - + ast_r() {_m = 0;} - - ast_r(const ast_r &other) : ast_i(other) { + + ast_r(const ast_r &other) : ast_i(other) { _m = other._m; if (_m) _m->inc_ref(_ast); } - + ast_r &operator=(const ast_r &other) { if(_ast) _m->dec_ref(_ast); @@ -107,12 +107,12 @@ class ast_r : public ast_i { if (_m) _m->inc_ref(_ast); return *this; } - - ~ast_r(){ + + ~ast_r() { if(_ast) _m->dec_ref(_ast); } - + ast_manager *mgr() const {return _m;} }; diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index c59dd0178..e4730ea63 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -29,6 +29,7 @@ #include "interp/iz3profiling.h" #include "interp/iz3interp.h" #include "interp/iz3proof_itp.h" +#include "ast/ast_pp.h" #include #include @@ -1851,6 +1852,21 @@ public: } break; } + case PR_TRANSITIVITY_STAR: { + // assume the premises are x = y, y = z, z = u, u = v, .. + + ast x = arg(conc(prem(proof,0)),0); + ast y = arg(conc(prem(proof,0)),1); + ast z = arg(conc(prem(proof,1)),1); + res = iproof->make_transitivity(x,y,z,args[0],args[1]); + + for (unsigned i = 2; i < nprems; ++i) { + y = z; + z = arg(conc(prem(proof,i)),1); + res = iproof->make_transitivity(x,y,z,res,args[i]); + } + break; + } case PR_QUANT_INTRO: case PR_MONOTONICITY: { @@ -2029,6 +2045,7 @@ public: break; } default: + IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); // pfgoto(proof); // SASSERT(0 && "translate_main: unsupported proof rule"); throw unsupported(); diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h index 519a252e0..8ecafbd3a 100755 --- a/src/interp/iz3translate.h +++ b/src/interp/iz3translate.h @@ -36,7 +36,7 @@ class iz3translation : public iz3base { /** This is thrown when the proof cannot be translated. */ struct unsupported: public iz3_exception { - unsupported(): iz3_exception("unsupported") {} + unsupported(): iz3_exception("unsupported") { } }; static iz3translation *create(iz3mgr &mgr, From e4b595d490dcad056b8afe5ffaadf71eb35a4357 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 16:10:20 -0700 Subject: [PATCH 41/57] add solver pool abstraction for Spacer Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 1 + src/muz/spacer/spacer_util.h | 9 - src/muz/spacer/spacer_virtual_solver.cpp | 9 +- src/opt/opt_solver.cpp | 3 +- src/sat/sat_solver/inc_sat_solver.cpp | 6 +- src/smt/smt_solver.cpp | 13 +- src/solver/CMakeLists.txt | 1 + src/solver/solver.cpp | 3 +- src/solver/solver.h | 10 +- src/solver/solver_pool.cpp | 320 ++++++++++++++++++ src/solver/solver_pool.h | 69 ++++ src/solver/tactic2solver.cpp | 7 +- .../portfolio/bounded_int2bv_solver.cpp | 5 +- src/tactic/portfolio/enum2bv_solver.cpp | 5 +- src/tactic/portfolio/pb2bv_solver.cpp | 5 +- src/util/stopwatch.h | 11 + 16 files changed, 435 insertions(+), 42 deletions(-) create mode 100644 src/solver/solver_pool.cpp create mode 100644 src/solver/solver_pool.h diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index e4a875005..0139cb0f0 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -44,6 +44,7 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) co return mk_string(m, str.c_str()); } else if (!s.bare_str()) { + len = 4; return mk_string(m, "null"); } else { diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index 546b7df5b..7fb17329e 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -74,15 +74,6 @@ inline std::ostream& operator<<(std::ostream& out, pp_level const& p) } -struct scoped_watch { - stopwatch &m_sw; - scoped_watch (stopwatch &sw, bool reset=false): m_sw(sw) - { - if(reset) { m_sw.reset(); } - m_sw.start (); - } - ~scoped_watch () {m_sw.stop ();} -}; typedef ptr_vector app_vector; diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index 89b9fb531..938e8cb94 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -189,15 +189,16 @@ void virtual_solver::push_core() m_context.push(); } } -void virtual_solver::pop_core(unsigned n) -{ +void virtual_solver::pop_core(unsigned n) { SASSERT(!m_pushed || get_scope_level() > 0); if (m_pushed) { SASSERT(!m_in_delay_scope); m_context.pop(n); m_pushed = get_scope_level() - n > 0; - } else - { m_in_delay_scope = get_scope_level() - n > 0; } + } + else { + m_in_delay_scope = get_scope_level() - n > 0; + } } void virtual_solver::get_unsat_core(ptr_vector &r) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 69b62083f..49b48e68f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -47,8 +47,9 @@ namespace opt { m_dump_benchmarks(false), m_first(true), m_was_unknown(false) { + solver::updt_params(p); m_params.updt_params(p); - if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { + if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { m_params.m_relevancy_lvl = 0; } // m_params.m_auto_config = false; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index be418cbc4..191c49294 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -69,7 +69,7 @@ class inc_sat_solver : public solver { public: inc_sat_solver(ast_manager& m, params_ref const& p): m(m), m_solver(p, m.limit(), 0), - m_params(p), m_optimize_model(false), + m_optimize_model(false), m_fmls(m), m_asmsf(m), m_fmls_head(0), @@ -79,7 +79,7 @@ public: m_dep_core(m), m_unknown("no reason given") { m_params.set_bool("elim_vars", false); - m_solver.updt_params(m_params); + updt_params(p); init_preprocess(); } @@ -237,7 +237,7 @@ public: sat::solver::collect_param_descrs(r); } virtual void updt_params(params_ref const & p) { - m_params = p; + solver::updt_params(p); m_params.set_bool("elim_vars", false); m_solver.updt_params(m_params); m_optimize_model = m_params.get_bool("optimize_model", false); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index d624a5c9a..539640913 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -31,7 +31,6 @@ namespace smt { class solver : public solver_na2as { smt_params m_smt_params; - params_ref m_params; smt::kernel m_context; progress_callback * m_callback; symbol m_logic; @@ -45,19 +44,15 @@ namespace smt { solver(ast_manager & m, params_ref const & p, symbol const & l) : solver_na2as(m), m_smt_params(p), - m_params(p), m_context(m, m_smt_params), m_minimizing_core(false), m_core_extend_patterns(false), m_core_extend_patterns_max_distance(UINT_MAX), - m_core_extend_nonlocal_patterns(false) { + m_core_extend_nonlocal_patterns(false) { m_logic = l; if (m_logic != symbol::null) m_context.set_logic(m_logic); - smt_params_helper smth(p); - m_core_extend_patterns = smth.core_extend_patterns(); - m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance(); - m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns(); + updt_params(p); } virtual solver * translate(ast_manager & m, params_ref const & p) { @@ -78,8 +73,8 @@ namespace smt { } virtual void updt_params(params_ref const & p) { + solver::updt_params(p); m_smt_params.updt_params(p); - m_params.copy(p); m_context.updt_params(p); smt_params_helper smth(p); m_core_extend_patterns = smth.core_extend_patterns(); @@ -165,7 +160,7 @@ namespace smt { r.push_back(m_context.get_unsat_core_expr(i)); } - if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) { + if (m_minimizing_core && smt_params_helper(get_params()).core_minimize()) { scoped_minimize_core scm(*this); mus mus(*this); mus.add_soft(r.size(), r.c_ptr()); diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 56864a691..1ffdc35e1 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -6,6 +6,7 @@ z3_add_component(solver smt_logics.cpp solver.cpp solver_na2as.cpp + solver_pool.cpp solver2tactic.cpp tactic2solver.cpp COMPONENT_DEPENDENCIES diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index cb7864268..bf53cb669 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -34,11 +34,12 @@ expr * solver::get_assertion(unsigned idx) const { return 0; } -std::ostream& solver::display(std::ostream & out) const { +std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const { expr_ref_vector fmls(get_manager()); get_assertions(fmls); ast_pp_util visitor(get_manager()); visitor.collect(fmls); + visitor.collect(n, assumptions); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); return out; diff --git a/src/solver/solver.h b/src/solver/solver.h index 00e3cf8e9..0a406455b 100644 --- a/src/solver/solver.h +++ b/src/solver/solver.h @@ -43,6 +43,7 @@ public: - results based on check_sat_result API */ class solver : public check_sat_result { + params_ref m_params; public: virtual ~solver() {} @@ -54,7 +55,12 @@ public: /** \brief Update the solver internal settings. */ - virtual void updt_params(params_ref const & p) { } + virtual void updt_params(params_ref const & p) { m_params.copy(p); } + + /** + \brief Retrieve set of parameters set on solver. + */ + virtual params_ref const& get_params() { return m_params; } /** \brief Store in \c r a description of the configuration @@ -175,7 +181,7 @@ public: /** \brief Display the content of this solver. */ - virtual std::ostream& display(std::ostream & out) const; + virtual std::ostream& display(std::ostream & out, unsigned n = 0, expr* const* assumptions = nullptr) const; class scoped_push { solver& s; diff --git a/src/solver/solver_pool.cpp b/src/solver/solver_pool.cpp new file mode 100644 index 000000000..c6c85ec29 --- /dev/null +++ b/src/solver/solver_pool.cpp @@ -0,0 +1,320 @@ +/** +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver_pool.cpp + +Abstract: + + Maintain a pool of solvers + +Author: + + Nikolaj Bjorner + +Notes: + +--*/ + +#include "solver/solver_pool.h" +#include "solver/solver_na2as.h" +#include "ast/proofs/proof_utils.h" +#include "ast/ast_util.h" + +class pool_solver : public solver_na2as { + solver_pool& m_pool; + app_ref m_pred; + proof_ref m_proof; + ref m_base; + expr_ref_vector m_assertions; + unsigned m_head; + expr_ref_vector m_flat; + bool m_pushed; + bool m_in_delayed_scope; + unsigned m_dump_counter; + + bool is_virtual() const { return !m.is_true(m_pred); } +public: + pool_solver(solver* b, solver_pool& pool, app_ref& pred): + solver_na2as(pred.get_manager()), + m_pool(pool), + m_pred(pred), + m_proof(m), + m_base(b), + m_assertions(m), + m_head(0), + m_flat(m), + m_pushed(false), + m_in_delayed_scope(false), + m_dump_counter(0) { + if (is_virtual()) { + solver_na2as::assert_expr(m.mk_true(), pred); + } + } + + virtual ~pool_solver() { + if (m_pushed) pop(get_scope_level()); + if (is_virtual()) { + m_pred = m.mk_not(m_pred); + m_base->assert_expr(m_pred); + } + } + + solver* base_solver() { return m_base.get(); } + + virtual solver* translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); return nullptr; } + virtual void updt_params(params_ref const& p) { solver::updt_params(p); m_base->updt_params(p); } + virtual void collect_param_descrs(param_descrs & r) { m_base->collect_param_descrs(r); } + virtual void collect_statistics(statistics & st) const { m_base->collect_statistics(st); } + + virtual void get_unsat_core(ptr_vector & r) { + m_base->get_unsat_core(r); + unsigned j = 0; + for (unsigned i = 0; i < r.size(); ++i) + if (m_pred != r[i]) + r[j++] = r[i]; + r.shrink(j); + } + + virtual unsigned get_num_assumptions() const { + unsigned sz = solver_na2as::get_num_assumptions(); + return is_virtual() ? sz - 1 : sz; + } + + virtual proof * get_proof() { + scoped_watch _t_(m_pool.m_proof_watch); + if (!m_proof.get()) { + elim_aux_assertions pc(m_pred); + m_proof = m_base->get_proof(); + pc(m, m_proof, m_proof); + } + return m_proof; + } + + void internalize_assertions() { + SASSERT(!m_pushed || m_head == m_assertions.size()); + for (unsigned sz = m_assertions.size(); m_head < sz; ++m_head) { + expr_ref f(m); + f = m.mk_implies(m_pred, (m_assertions.get(m_head))); + m_base->assert_expr(f); + } + } + + virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) { + SASSERT(!m_pushed || get_scope_level() > 0); + m_proof.reset(); + scoped_watch _t_(m_pool.m_check_watch); + m_pool.m_stats.m_num_checks++; + + stopwatch sw; + sw.start(); + internalize_assertions(); + lbool res = m_base->check_sat(num_assumptions, assumptions); + sw.stop(); + switch (res) { + case l_true: + m_pool.m_check_sat_watch.add(sw); + m_pool.m_stats.m_num_sat_checks++; + break; + case l_undef: + m_pool.m_check_undef_watch.add(sw); + m_pool.m_stats.m_num_undef_checks++; + break; + default: + break; + } + set_status(res); + + if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) { + std::stringstream file_name; + file_name << "virt_solver"; + if (is_virtual()) { file_name << "_" << m_pred->get_decl()->get_name(); } + file_name << "_" << (m_dump_counter++) << ".smt2"; + + std::ofstream out(file_name.str().c_str()); + if (!out) { verbose_stream() << "could not open file " << file_name.str() << " for output\n"; } + + out << "(set-info :status "; + switch (res) { + case l_true: out << "sat"; break; + case l_false: out << "unsat"; break; + case l_undef: out << "unknown"; break; + } + out << ")\n"; + m_base->display(out, num_assumptions, assumptions); + bool first = true; + out << "(check-sat"; + for (unsigned i = 0; i < num_assumptions; ++i) { + out << " " << mk_pp(assumptions[i], m); + } + out << ")"; + out << "(exit)\n"; + ::statistics st; + m_base->collect_statistics(st); + st.update("time", sw.get_seconds()); + st.display_smt2(out); + out.close(); + } + return res; + } + + virtual void push_core() { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_in_delayed_scope) { + // second push + internalize_assertions(); + m_base->push(); + m_pushed = true; + m_in_delayed_scope = false; + } + + if (!m_pushed) { + m_in_delayed_scope = true; + } + else { + SASSERT(m_pushed); + SASSERT(!m_in_delayed_scope); + m_base->push(); + } + } + + virtual void pop_core(unsigned n) { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m_pushed) { + SASSERT(!m_in_delayed_scope); + m_base->pop(n); + m_pushed = get_scope_level() - n > 0; + } + else { + m_in_delayed_scope = get_scope_level() - n > 0; + } + } + + virtual void assert_expr(expr * e) { + SASSERT(!m_pushed || get_scope_level() > 0); + if (m.is_true(e)) return; + if (m_in_delayed_scope) { + internalize_assertions(); + m_base->push(); + m_pushed = true; + m_in_delayed_scope = false; + } + + if (m_pushed) { + m_base->assert_expr(e); + } + else { + m_flat.push_back(e); + flatten_and(m_flat); + m_assertions.append(m_flat); + m_flat.reset(); + } + } + + virtual void get_model(model_ref & _m) { m_base->get_model(_m); } + + virtual expr * get_assumption(unsigned idx) const { + return solver_na2as::get_assumption(idx + is_virtual()); + } + + virtual std::string reason_unknown() const { return m_base->reason_unknown(); } + virtual void set_reason_unknown(char const* msg) { return m_base->set_reason_unknown(msg); } + virtual void get_labels(svector & r) { return m_base->get_labels(r); } + virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); } + + virtual ast_manager& get_manager() const { return m_base->get_manager(); } + + void refresh(solver* new_base) { + SASSERT(!m_pushed); + m_head = 0; + m_base = new_base; + } + + void reset() { + SASSERT(!m_pushed); + m_head = 0; + m_assertions.reset(); + m_pool.refresh(m_base.get()); + } +}; + +solver_pool::solver_pool(solver* base_solver, unsigned num_solvers_per_pool): + m_base_solver(base_solver), + m_num_solvers_per_pool(num_solvers_per_pool), + m_num_solvers_in_last_pool(0) +{} + + +ptr_vector solver_pool::get_base_solvers() const { + ptr_vector solvers; + for (solver* s0 : m_solvers) { + pool_solver* s = dynamic_cast(s0); + if (!solvers.contains(s->base_solver())) { + solvers.push_back(s->base_solver()); + } + } + return solvers; +} + +void solver_pool::collect_statistics(statistics &st) const { + ptr_vector solvers = get_base_solvers(); + for (solver* s : solvers) s->collect_statistics(st); + st.update("time.pool_solver.smt.total", m_check_watch.get_seconds()); + st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds()); + st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds()); + st.update("time.pool_solver.proof", m_proof_watch.get_seconds()); + st.update("pool_solver.checks", m_stats.m_num_checks); + st.update("pool_solver.checks.sat", m_stats.m_num_sat_checks); + st.update("pool_solver.checks.undef", m_stats.m_num_undef_checks); +} + +void solver_pool::reset_statistics() { +#if 0 + ptr_vector solvers = get_base_solvers(); + for (solver* s : solvers) { + s->reset_statistics(); + } +#endif + m_stats.reset(); + m_check_sat_watch.reset(); + m_check_undef_watch.reset(); + m_check_watch.reset(); + m_proof_watch.reset(); +} + +solver* solver_pool::mk_solver() { + ref base_solver; + ast_manager& m = m_base_solver->get_manager(); + if (m_solvers.empty() || m_num_solvers_in_last_pool == m_num_solvers_per_pool) { + base_solver = m_base_solver->translate(m, m_base_solver->get_params()); + m_num_solvers_in_last_pool = 0; + } + else { + base_solver = dynamic_cast(m_solvers.back())->base_solver(); + } + m_num_solvers_in_last_pool++; + std::stringstream name; + name << "vsolver#" << m_solvers.size(); + app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m); + pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred); + m_solvers.push_back(solver); + return solver; +} + +void solver_pool::reset_solver(solver* s) { + pool_solver* ps = dynamic_cast(s); + SASSERT(ps); + if (ps) ps->reset(); +} + +void solver_pool::refresh(solver* base_solver) { + ast_manager& m = m_base_solver->get_manager(); + ref new_base = m_base_solver->translate(m, m_base_solver->get_params()); + for (solver* s0 : m_solvers) { + pool_solver* s = dynamic_cast(s0); + if (base_solver == s->base_solver()) { + s->refresh(new_base.get()); + } + } +} diff --git a/src/solver/solver_pool.h b/src/solver/solver_pool.h new file mode 100644 index 000000000..d676ca54d --- /dev/null +++ b/src/solver/solver_pool.h @@ -0,0 +1,69 @@ +/** +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver_pool.h + +Abstract: + + Maintain a pool of solvers + +Author: + + Nikolaj Bjorner + Arie Gurfinkel + +Notes: + + This is a revision of spacer_virtual_solver by Arie Gurfinkel + +--*/ +#ifndef SOLVER_POOL_H_ +#define SOLVER_POOL_H_ + +#include "solver/solver.h" +#include "util/stopwatch.h" + +class pool_solver; + +class solver_pool { + + friend class pool_solver; + + struct stats { + unsigned m_num_checks; + unsigned m_num_sat_checks; + unsigned m_num_undef_checks; + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + }; + + ref m_base_solver; + unsigned m_num_solvers_per_pool; + unsigned m_num_solvers_in_last_pool; + sref_vector m_solvers; + stats m_stats; + + stopwatch m_check_watch; + stopwatch m_check_sat_watch; + stopwatch m_check_undef_watch; + stopwatch m_proof_watch; + + void refresh(solver* s); + + ptr_vector get_base_solvers() const; + +public: + solver_pool(solver* base_solver, unsigned num_solvers_per_pool); + + void collect_statistics(statistics &st) const; + void reset_statistics(); + + solver* mk_solver(); + + void reset_solver(solver* s); +}; + + +#endif diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index d7e7fbb6e..a24f1d4c7 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -37,7 +37,6 @@ class tactic2solver : public solver_na2as { ref m_result; tactic_ref m_tactic; symbol m_logic; - params_ref m_params; bool m_produce_models; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -85,7 +84,7 @@ tactic2solver::tactic2solver(ast_manager & m, tactic * t, params_ref const & p, m_tactic = t; m_logic = logic; - m_params = p; + solver::updt_params(p); m_produce_models = produce_models; m_produce_proofs = produce_proofs; @@ -96,7 +95,7 @@ tactic2solver::~tactic2solver() { } void tactic2solver::updt_params(params_ref const & p) { - m_params.append(p); + solver::updt_params(p); } void tactic2solver::collect_param_descrs(param_descrs & r) { @@ -129,7 +128,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_result = alloc(simple_check_sat_result, m); m_tactic->cleanup(); m_tactic->set_logic(m_logic); - m_tactic->updt_params(m_params); // parameters are allowed to overwrite logic. + m_tactic->updt_params(get_params()); // parameters are allowed to overwrite logic. goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores); unsigned sz = m_assertions.size(); diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/portfolio/bounded_int2bv_solver.cpp index 2f66d7a53..58078e106 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/portfolio/bounded_int2bv_solver.cpp @@ -33,7 +33,6 @@ Notes: class bounded_int2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; mutable bv_util m_bv; mutable arith_util m_arith; mutable expr_ref_vector m_assertions; @@ -53,7 +52,6 @@ public: bounded_int2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_bv(m), m_arith(m), m_assertions(m), @@ -63,6 +61,7 @@ public: m_rewriter_ctx(m, p), m_rewriter(m, m_rewriter_ctx) { + solver::updt_params(p); m_bounds.push_back(alloc(bound_manager, m)); } @@ -131,7 +130,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 5880302d9..dd0ee7c4b 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -33,7 +33,6 @@ Notes: class enum2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; ref m_solver; enum2bv_rewriter m_rewriter; @@ -42,10 +41,10 @@ public: enum2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_solver(s), m_rewriter(m, p) { + solver::updt_params(p); } virtual ~enum2bv_solver() {} @@ -78,7 +77,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 81cc43685..a06ff77c0 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -26,7 +26,6 @@ Notes: class pb2bv_solver : public solver_na2as { ast_manager& m; - params_ref m_params; mutable expr_ref_vector m_assertions; mutable ref m_solver; mutable pb2bv_rewriter m_rewriter; @@ -36,11 +35,11 @@ public: pb2bv_solver(ast_manager& m, params_ref const& p, solver* s): solver_na2as(m), m(m), - m_params(p), m_assertions(m), m_solver(s), m_rewriter(m, p) { + solver::updt_params(p); } virtual ~pb2bv_solver() {} @@ -70,7 +69,7 @@ public: return m_solver->check_sat(num_assumptions, assumptions); } - virtual void updt_params(params_ref const & p) { m_solver->updt_params(p); } + virtual void updt_params(params_ref const & p) { solver::updt_params(p); m_solver->updt_params(p); } virtual void collect_param_descrs(param_descrs & r) { m_solver->collect_param_descrs(r); } virtual void set_produce_models(bool f) { m_solver->set_produce_models(f); } virtual void set_progress_callback(progress_callback * callback) { m_solver->set_progress_callback(callback); } diff --git a/src/util/stopwatch.h b/src/util/stopwatch.h index 7f2ed3245..9ba707af0 100644 --- a/src/util/stopwatch.h +++ b/src/util/stopwatch.h @@ -185,4 +185,15 @@ public: #endif +struct scoped_watch { + stopwatch &m_sw; + scoped_watch (stopwatch &sw, bool reset=false): m_sw(sw) { + if (reset) m_sw.reset(); + m_sw.start(); + } + ~scoped_watch() { + m_sw.stop (); + } +}; + #endif From 60b970b9babafae7dfdaa888709f280c1cb82b32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 16:23:13 -0700 Subject: [PATCH 42/57] add proofs dependency to solver Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 6e7024b3f..05190f217 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -37,13 +37,13 @@ def init_project_def(): add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') - add_lib('solver', ['model', 'tactic']) + add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') + add_lib('solver', ['model', 'tactic', 'proofs']) add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('interp', ['solver']) add_lib('cmd_context', ['solver', 'rewriter', 'interp']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') - add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') From b556f3ca42491ba2b59ca86a051de36a699064fa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 16:41:29 -0700 Subject: [PATCH 43/57] fix stack overflow Signed-off-by: Nikolaj Bjorner --- src/smt/smt_solver.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 539640913..1f9ad3ef7 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -29,7 +29,7 @@ Notes: namespace smt { - class solver : public solver_na2as { + class smt_solver : public solver_na2as { smt_params m_smt_params; smt::kernel m_context; progress_callback * m_callback; @@ -41,7 +41,7 @@ namespace smt { obj_map m_name2assertion; public: - solver(ast_manager & m, params_ref const & p, symbol const & l) : + smt_solver(ast_manager & m, params_ref const & p, symbol const & l) : solver_na2as(m), m_smt_params(p), m_context(m, m_smt_params), @@ -58,7 +58,7 @@ namespace smt { virtual solver * translate(ast_manager & m, params_ref const & p) { ast_translation translator(get_manager(), m); - solver * result = alloc(solver, m, p, m_logic); + smt_solver * result = alloc(smt_solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); for (auto & kv : m_name2assertion) @@ -68,7 +68,7 @@ namespace smt { return result; } - virtual ~solver() { + virtual ~smt_solver() { dec_ref_values(get_manager(), m_name2assertion); } @@ -141,9 +141,9 @@ namespace smt { } struct scoped_minimize_core { - solver& s; + smt_solver& s; expr_ref_vector m_assumptions; - scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) { + scoped_minimize_core(smt_solver& s) : s(s), m_assumptions(s.m_assumptions) { s.m_minimizing_core = true; s.m_assumptions.reset(); } @@ -341,22 +341,16 @@ namespace smt { void add_nonlocal_pattern_literals_to_core(ptr_vector & core) { ast_manager & m = get_manager(); - - obj_map::iterator it = m_name2assertion.begin(); - obj_map::iterator end = m_name2assertion.end(); - for (unsigned i = 0; it != end; it++, i++) { - expr_ref name(it->m_key, m); - expr_ref assrtn(it->m_value, m); + for (auto const& kv : m_name2assertion) { + expr_ref name(kv.m_key, m); + expr_ref assrtn(kv.m_value, m); if (!core.contains(name)) { func_decl_set pattern_fds, body_fds; collect_pattern_fds(assrtn, pattern_fds); collect_body_func_decls(assrtn, body_fds); - func_decl_set::iterator pit = pattern_fds.begin(); - func_decl_set::iterator pend= pattern_fds.end(); - for (; pit != pend; pit++) { - func_decl * fd = *pit; + for (func_decl *fd : pattern_fds) { if (!body_fds.contains(fd)) { core.insert(name); break; @@ -369,7 +363,7 @@ namespace smt { }; solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) { - return alloc(smt::solver, m, p, logic); + return alloc(smt::smt_solver, m, p, logic); } class smt_solver_factory : public solver_factory { From 2227db215ed18d524c4e8a3c0e1f0d03bc63877f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 16:58:16 -0700 Subject: [PATCH 44/57] fix build break with virtual method override Signed-off-by: Nikolaj Bjorner --- src/solver/combined_solver.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 8f37224ad..81e10e443 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -147,6 +147,7 @@ public: } virtual void updt_params(params_ref const & p) { + solver::updt_params(p); m_solver1->updt_params(p); m_solver2->updt_params(p); updt_local_params(p); @@ -280,8 +281,8 @@ public: return m_solver2->get_assumption(idx - c1); } - virtual std::ostream& display(std::ostream & out) const { - return m_solver1->display(out); + virtual std::ostream& display(std::ostream & out, unsigned n, expr* const* es) const { + return m_solver1->display(out, n, es); } virtual void collect_statistics(statistics & st) const { From 9e20bfe7f9268eea5fec436e179a50868fb69162 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Oct 2017 17:23:35 -0700 Subject: [PATCH 45/57] fix virtual method override Signed-off-by: Nikolaj Bjorner --- src/muz/spacer/spacer_itp_solver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/muz/spacer/spacer_itp_solver.h b/src/muz/spacer/spacer_itp_solver.h index cab19c8ef..8194379b8 100644 --- a/src/muz/spacer/spacer_itp_solver.h +++ b/src/muz/spacer/spacer_itp_solver.h @@ -134,8 +134,8 @@ public: {return m_solver.get_num_assumptions();} virtual expr * get_assumption(unsigned idx) const {return m_solver.get_assumption(idx);} - virtual std::ostream &display(std::ostream &out) const - { return m_solver.display(out); } + virtual std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const + { return m_solver.display(out, n, es); } /* check_sat_result interface */ From e50470f2c4d561e42989d74b1a49e606c8e84415 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 30 Oct 2017 18:24:38 +0000 Subject: [PATCH 46/57] Added support for MSYS2 --- scripts/mk_util.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 6f3052f6e..8d4fe5552 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -72,6 +72,7 @@ IS_FREEBSD=False IS_OPENBSD=False IS_CYGWIN=False IS_CYGWIN_MINGW=False +IS_MSYS2=False VERBOSE=True DEBUG_MODE=False SHOW_CPPS = True @@ -152,6 +153,9 @@ def is_cygwin(): def is_cygwin_mingw(): return IS_CYGWIN_MINGW +def is_msys2(): + return IS_MSYS2 + def norm_path(p): return os.path.expanduser(os.path.normpath(p)) @@ -227,7 +231,7 @@ def rmf(fname): def exec_compiler_cmd(cmd): r = exec_cmd(cmd) - if is_windows() or is_cygwin_mingw(): + if is_windows() or is_cygwin_mingw() or is_cygwin() or is_msys2(): rmf('a.exe') else: rmf('a.out') @@ -606,6 +610,13 @@ elif os.name == 'posix': IS_CYGWIN=True if (CC != None and "mingw" in CC): IS_CYGWIN_MINGW=True + elif os.uname()[0].startswith('MSYS_NT'): + IS_MSYS2=True + if os.uname()[4] == 'x86_64': + LINUX_X64=True + else: + LINUX_X64=False + def display_help(exit_code): print("mk_make.py: Z3 Makefile generator\n") @@ -1229,7 +1240,7 @@ def get_so_ext(): sysname = os.uname()[0] if sysname == 'Darwin': return 'dylib' - elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD': + elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD' or sysname.startswith('MSYS_NT'): return 'so' elif sysname == 'CYGWIN': return 'dll' @@ -1783,6 +1794,8 @@ class JavaDLLComponent(Component): t = t.replace('PLATFORM', 'openbsd') elif IS_CYGWIN: t = t.replace('PLATFORM', 'cygwin') + elif IS_MSYS2: + t = t.replace('PLATFORM', 'win32') else: t = t.replace('PLATFORM', 'win32') out.write(t) @@ -2446,7 +2459,7 @@ def mk_config(): if sysname == 'Darwin': SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' - elif sysname == 'Linux': + elif sysname == 'Linux' or sysname.startswith('MSYS_NT'): CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS OS_DEFINES = '-D_LINUX_' SO_EXT = '.so' @@ -2466,10 +2479,10 @@ def mk_config(): SO_EXT = '.so' SLIBFLAGS = '-shared' elif sysname[:6] == 'CYGWIN': - CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS + CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS OS_DEFINES = '-D_CYGWIN' - SO_EXT = '.dll' - SLIBFLAGS = '-shared' + SO_EXT = '.dll' + SLIBFLAGS = '-shared' else: raise MKException('Unsupported platform: %s' % sysname) if is64(): From 6e31d9c3f55ef3745d6f5929864cf6e96c79573d Mon Sep 17 00:00:00 2001 From: Murphy Berzish Date: Mon, 30 Oct 2017 14:34:27 -0400 Subject: [PATCH 47/57] internalize free var before iterating eqc in theory_str --- src/smt/theory_str.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index fc8122800..f47d6011f 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -10484,6 +10484,9 @@ namespace smt { // iterate parents if (standAlone) { // I hope this works! + if (!ctx.e_internalized(freeVar)) { + ctx.internalize(freeVar, false); + } enode * e_freeVar = ctx.get_enode(freeVar); enode_vector::iterator it = e_freeVar->begin_parents(); for (; it != e_freeVar->end_parents(); ++it) { From 34f24aee720721b844fb566d852ef88934c31e00 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Oct 2017 13:50:31 -0500 Subject: [PATCH 48/57] fix order of instantiation for recursive functions, #1274 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c508a65cb..7b508c7d8 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4389,7 +4389,8 @@ namespace smt { subst.push_back(arg); } expr_ref bodyr(m); - var_subst sub(m, false); + var_subst sub(m, true); + TRACE("context", tout << expr_ref(q, m) << " " << subst << "\n";); sub(body, subst.size(), subst.c_ptr(), bodyr); func_decl* f = to_app(fn)->get_decl(); func_interp* fi = alloc(func_interp, m, f->get_arity()); From 2a459c5ff648d0eed0be10d1f1c8503f48533200 Mon Sep 17 00:00:00 2001 From: Paul Ehrlich Date: Wed, 1 Nov 2017 12:02:48 +0100 Subject: [PATCH 49/57] MSYS offers a MINGW shell as well. (uses different os.uname()) --- scripts/mk_util.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8d4fe5552..d44e8f416 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -610,7 +610,7 @@ elif os.name == 'posix': IS_CYGWIN=True if (CC != None and "mingw" in CC): IS_CYGWIN_MINGW=True - elif os.uname()[0].startswith('MSYS_NT'): + elif os.uname()[0].startswith('MSYS_NT') or os.uname()[0].startswith('MINGW'): IS_MSYS2=True if os.uname()[4] == 'x86_64': LINUX_X64=True @@ -1240,7 +1240,7 @@ def get_so_ext(): sysname = os.uname()[0] if sysname == 'Darwin': return 'dylib' - elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD' or sysname.startswith('MSYS_NT'): + elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'): return 'so' elif sysname == 'CYGWIN': return 'dll' @@ -1888,7 +1888,6 @@ class MLComponent(Component): def _init_ocamlfind_paths(self): """ Initialises self.destdir and self.ldconf - Do not call this from the MLComponent constructor because OCAMLFIND has not been checked at that point """ @@ -2459,7 +2458,7 @@ def mk_config(): if sysname == 'Darwin': SO_EXT = '.dylib' SLIBFLAGS = '-dynamiclib' - elif sysname == 'Linux' or sysname.startswith('MSYS_NT'): + elif sysname == 'Linux' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'): CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS OS_DEFINES = '-D_LINUX_' SO_EXT = '.so' @@ -3173,7 +3172,6 @@ class MakeRuleCmd(object): """ These class methods provide a convenient way to emit frequently needed commands used in Makefile rules - Note that several of the method are meant for use during ``make install`` and ``make uninstall``. These methods correctly use ``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferrable @@ -3349,10 +3347,8 @@ def configure_file(template_file_path, output_file_path, substitutions): Read a template file ``template_file_path``, perform substitutions found in the ``substitutions`` dictionary and write the result to the output file ``output_file_path``. - The template file should contain zero or more template strings of the form ``@NAME@``. - The substitutions dictionary maps old strings (without the ``@`` symbols) to their replacements. """ From 429edf175fd74513d44f6ee50648e29dc89fcb7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Nov 2017 19:16:04 -0800 Subject: [PATCH 50/57] fix model converter bug in coi-filter #1241 Signed-off-by: Nikolaj Bjorner --- src/muz/dataflow/dataflow.h | 69 ++++++++++--------------- src/muz/transforms/dl_mk_coi_filter.cpp | 60 +++++++++++---------- 2 files changed, 59 insertions(+), 70 deletions(-) diff --git a/src/muz/dataflow/dataflow.h b/src/muz/dataflow/dataflow.h index 5e91a0149..e9e543b2d 100644 --- a/src/muz/dataflow/dataflow.h +++ b/src/muz/dataflow/dataflow.h @@ -62,8 +62,7 @@ namespace datalog { rule_set::decl2rules m_body2rules; void init_bottom_up() { - for (rule_set::iterator it = m_rules.begin(); it != m_rules.end(); ++it) { - rule* cur = *it; + for (rule* cur : m_rules) { for (unsigned i = 0; i < cur->get_uninterpreted_tail_size(); ++i) { func_decl *d = cur->get_decl(i); rule_set::decl2rules::obj_map_entry *e = m_body2rules.insert_if_not_there2(d, 0); @@ -83,31 +82,25 @@ namespace datalog { } void init_top_down() { - const func_decl_set& output_preds = m_rules.get_output_predicates(); - for (func_decl_set::iterator I = output_preds.begin(), - E = output_preds.end(); I != E; ++I) { - func_decl* sym = *I; + for (func_decl* sym : m_rules.get_output_predicates()) { TRACE("dl", tout << sym->get_name() << "\n";); const rule_vector& output_rules = m_rules.get_predicate_rules(sym); - for (unsigned i = 0; i < output_rules.size(); ++i) { - m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_down(m_context, output_rules[i]); + for (rule* r : output_rules) { + m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_down(m_context, r); m_todo[m_todo_idx].insert(sym); } } } void step_bottom_up() { - for(todo_set::iterator I = m_todo[m_todo_idx].begin(), - E = m_todo[m_todo_idx].end(); I!=E; ++I) { + for (func_decl* f : m_todo[m_todo_idx]) { ptr_vector * rules; - if (!m_body2rules.find(*I, rules)) + if (!m_body2rules.find(f, rules)) continue; - - for (ptr_vector::iterator I2 = rules->begin(), - E2 = rules->end(); I2 != E2; ++I2) { - func_decl* head_sym = (*I2)->get_head()->get_decl(); - fact_reader tail_facts(m_facts, *I2); - bool new_info = m_facts.insert_if_not_there2(head_sym, Fact())->get_data().m_value.propagate_up(m_context, *I2, tail_facts); + for (rule* r : *rules) { + func_decl* head_sym = r->get_head()->get_decl(); + fact_reader tail_facts(m_facts, r); + bool new_info = m_facts.insert_if_not_there2(head_sym, Fact())->get_data().m_value.propagate_up(m_context, r, tail_facts); if (new_info) { m_todo[!m_todo_idx].insert(head_sym); } @@ -119,15 +112,11 @@ namespace datalog { } void step_top_down() { - for(todo_set::iterator I = m_todo[m_todo_idx].begin(), - E = m_todo[m_todo_idx].end(); I!=E; ++I) { - func_decl* head_sym = *I; + for (func_decl* head_sym : m_todo[m_todo_idx]) { // We can't use a reference here because we are changing the map while using the reference const Fact head_fact = m_facts.get(head_sym, Fact::null_fact); const rule_vector& deps = m_rules.get_predicate_rules(head_sym); - const unsigned deps_size = deps.size(); - for (unsigned i = 0; i < deps_size; ++i) { - rule *trg_rule = deps[i]; + for (rule* trg_rule : deps) { fact_writer writer(m_facts, trg_rule, m_todo[!m_todo_idx]); // Generate new facts head_fact.propagate_down(m_context, trg_rule, writer); @@ -146,16 +135,13 @@ namespace datalog { dataflow_engine(typename Fact::ctx_t& ctx, const rule_set& rules) : m_rules(rules), m_todo_idx(0), m_context(ctx) {} ~dataflow_engine() { - for (rule_set::decl2rules::iterator it = m_body2rules.begin(); it != m_body2rules.end(); ++it) { - dealloc(it->m_value); - } + for (auto & kv : m_body2rules) + dealloc(kv.m_value); } void dump(std::ostream& outp) { obj_hashtable visited; - for (rule_set::iterator I = m_rules.begin(), - E = m_rules.end(); I != E; ++I) { - const rule* r = *I; + for (rule const* r : m_rules) { func_decl* head_decl = r->get_decl(); obj_hashtable::entry *dummy; if (visited.insert_if_not_there_core(head_decl, dummy)) { @@ -194,30 +180,29 @@ namespace datalog { iterator end() const { return m_facts.end(); } void join(const dataflow_engine& oth) { - for (typename fact_db::iterator I = oth.m_facts.begin(), - E = oth.m_facts.end(); I != E; ++I) { + for (auto const& kv : oth.m_facts) { typename fact_db::entry* entry; - if (m_facts.insert_if_not_there_core(I->m_key, entry)) { - entry->get_data().m_value = I->m_value; + if (m_facts.insert_if_not_there_core(kv.m_key, entry)) { + entry->get_data().m_value = kv.m_value; } else { - entry->get_data().m_value.join(m_context, I->m_value); + entry->get_data().m_value.join(m_context, kv.m_value); } } } void intersect(const dataflow_engine& oth) { vector to_delete; - for (typename fact_db::iterator I = m_facts.begin(), - E = m_facts.end(); I != E; ++I) { + for (auto const& kv : m_facts) { - if (typename fact_db::entry *entry = oth.m_facts.find_core(I->m_key)) { - I->m_value.intersect(m_context, entry->get_data().m_value); - } else { - to_delete.push_back(I->m_key); + if (typename fact_db::entry *entry = oth.m_facts.find_core(kv.m_key)) { + kv.m_value.intersect(m_context, entry->get_data().m_value); + } + else { + to_delete.push_back(kvm_key); } } - for (unsigned i = 0; i < to_delete.size(); ++i) { - m_facts.erase(to_delete[i]); + for (func_decl* f : to_delete) { + m_facts.erase(f); } } }; diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 31188bf43..3ea0e305a 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -21,6 +21,7 @@ Author: #include "muz/dataflow/dataflow.h" #include "muz/dataflow/reachability.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "tactic/extension_model_converter.h" namespace datalog { @@ -33,20 +34,28 @@ namespace datalog { rule_set * mk_coi_filter::bottom_up(rule_set const & source) { dataflow_engine engine(source.get_manager(), source); engine.run_bottom_up(); + func_decl_set unreachable; scoped_ptr res = alloc(rule_set, m_context); res->inherit_predicates(source); - for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { - rule * r = *it; - + for (rule* r : source) { bool new_tail = false; bool contained = true; + m_new_tail.reset(); + m_new_tail_neg.reset(); for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { - if (m_context.has_facts(r->get_decl(i))) { + func_decl* decl_i = r->get_decl(i); + if (m_context.has_facts(decl_i)) { return 0; } + bool reachable = engine.get_fact(decl_i).is_reachable(); + + if (!reachable) { + unreachable.insert(decl_i); + } + if (r->is_neg_tail(i)) { - if (!engine.get_fact(r->get_decl(i)).is_reachable()) { + if (!reachable) { if (!new_tail) { for (unsigned j = 0; j < i; ++j) { m_new_tail.push_back(r->get_tail(j)); @@ -60,10 +69,9 @@ namespace datalog { m_new_tail_neg.push_back(true); } } - else { SASSERT(!new_tail); - if (!engine.get_fact(r->get_decl(i)).is_reachable()) { + if (!reachable) { contained = false; break; } @@ -78,24 +86,26 @@ namespace datalog { res->add_rule(r); } } - m_new_tail.reset(); - m_new_tail_neg.reset(); } if (res->get_num_rules() == source.get_num_rules()) { TRACE("dl", tout << "No transformation\n";); res = 0; - } else { + } + else { res->close(); } - + // set to false each unreached predicate - if (m_context.get_model_converter()) { + if (res && m_context.get_model_converter()) { extension_model_converter* mc0 = alloc(extension_model_converter, m); - for (dataflow_engine::iterator it = engine.begin(); it != engine.end(); it++) { - if (!it->m_value.is_reachable()) { - mc0->insert(it->m_key, m.mk_false()); + for (auto const& kv : engine) { + if (!kv.m_value.is_reachable()) { + mc0->insert(kv.m_key, m.mk_false()); } } + for (func_decl* f : unreachable) { + mc0->insert(f, m.mk_false()); + } m_context.add_model_converter(mc0); } CTRACE("dl", 0 != res, res->display(tout);); @@ -109,9 +119,7 @@ namespace datalog { scoped_ptr res = alloc(rule_set, m_context); res->inherit_predicates(source); - rule_set::iterator rend = source.end(); - for (rule_set::iterator rit = source.begin(); rit != rend; ++rit) { - rule * r = *rit; + for (rule * r : source) { func_decl * pred = r->get_decl(); if (engine.get_fact(pred).is_reachable()) { res->add_rule(r); @@ -125,14 +133,12 @@ namespace datalog { res = 0; } if (res && m_context.get_model_converter()) { - func_decl_set::iterator end = pruned_preds.end(); - func_decl_set::iterator it = pruned_preds.begin(); extension_model_converter* mc0 = alloc(extension_model_converter, m); - for (; it != end; ++it) { - const rule_vector& rules = source.get_predicate_rules(*it); + for (func_decl* f : pruned_preds) { + const rule_vector& rules = source.get_predicate_rules(f); expr_ref_vector fmls(m); - for (unsigned i = 0; i < rules.size(); ++i) { - app* head = rules[i]->get_head(); + for (rule * r : rules) { + app* head = r->get_head(); expr_ref_vector conj(m); for (unsigned j = 0; j < head->get_num_args(); ++j) { expr* arg = head->get_arg(j); @@ -140,11 +146,9 @@ namespace datalog { conj.push_back(m.mk_eq(m.mk_var(j, m.get_sort(arg)), arg)); } } - fmls.push_back(m.mk_and(conj.size(), conj.c_ptr())); + fmls.push_back(mk_and(conj)); } - expr_ref fml(m); - fml = m.mk_or(fmls.size(), fmls.c_ptr()); - mc0->insert(*it, fml); + mc0->insert(f, mk_or(fmls)); } m_context.add_model_converter(mc0); } From 5bb5a50490c5aecea92c7dba56033cdc24b6e8e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Nov 2017 19:24:05 -0800 Subject: [PATCH 51/57] fix build Signed-off-by: Nikolaj Bjorner --- src/muz/dataflow/dataflow.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/muz/dataflow/dataflow.h b/src/muz/dataflow/dataflow.h index e9e543b2d..6f3010940 100644 --- a/src/muz/dataflow/dataflow.h +++ b/src/muz/dataflow/dataflow.h @@ -184,21 +184,22 @@ namespace datalog { typename fact_db::entry* entry; if (m_facts.insert_if_not_there_core(kv.m_key, entry)) { entry->get_data().m_value = kv.m_value; - } else { + } + else { entry->get_data().m_value.join(m_context, kv.m_value); } } } void intersect(const dataflow_engine& oth) { - vector to_delete; + ptr_vector to_delete; for (auto const& kv : m_facts) { if (typename fact_db::entry *entry = oth.m_facts.find_core(kv.m_key)) { kv.m_value.intersect(m_context, entry->get_data().m_value); } else { - to_delete.push_back(kvm_key); + to_delete.push_back(kv.m_key); } } for (func_decl* f : to_delete) { From 53ed1bb862cf7b1fd70eb71bf7e236895b01d35c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 02:05:00 -0800 Subject: [PATCH 52/57] fix segfault reported as part of #1241 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic_def.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 203dd24d2..59f5521c5 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -683,7 +683,9 @@ void theory_diff_logic::set_neg_cycle_conflict() { vector params; if (get_manager().proofs_enabled()) { params.push_back(parameter(symbol("farkas"))); - params.resize(lits.size()+1, parameter(rational(1))); + for (unsigned i = 0; i <= lits.size(); ++i) { + params.push_back(parameter(rational(1))); + } } ctx.set_conflict( From 16bab71df21f60f2cdb0faab438802f7a8c66128 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 02:18:55 -0800 Subject: [PATCH 53/57] remove asserts for proof generation to enable mode switch in spacer virtual solver Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 3dbd0bc69..8c74cbe83 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2842,21 +2842,18 @@ proof * ast_manager::mk_distributivity(expr * s, expr * r) { } proof * ast_manager::mk_rewrite(expr * s, expr * t) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); } proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); } proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; ptr_buffer args; @@ -2866,42 +2863,36 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr } proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); } proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); } proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); } proof * ast_manager::mk_der(quantifier * q, expr * e) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); } proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; vector params; @@ -2937,7 +2928,6 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const { } proof * ast_manager::mk_def_axiom(expr * ax) { - SASSERT(proofs_enabled()); if (proofs_disabled()) return m_undef_proof; return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); From 0f2b1ae7c81f1c381332a5aafddd29c73856f0c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 02:35:10 -0800 Subject: [PATCH 54/57] fix proof mode related segfaults #1241 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 40 ++++++++++++++++----------------- src/ast/rewriter/rewriter_def.h | 3 +-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8c74cbe83..7eae396ff 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2626,7 +2626,7 @@ bool ast_manager::is_fully_interp(sort * s) const { proof * ast_manager::mk_proof(family_id fid, decl_kind k, unsigned num_args, expr * const * args) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(fid, k, num_args, args); } @@ -2843,19 +2843,19 @@ proof * ast_manager::mk_distributivity(expr * s, expr * r) { proof * ast_manager::mk_rewrite(expr * s, expr * t) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); } proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); } proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; ptr_buffer args; args.append(num_proofs, (expr**) proofs); args.push_back(mk_eq(s, t)); @@ -2864,37 +2864,37 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); } proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); } proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); } proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); } proof * ast_manager::mk_der(quantifier * q, expr * e) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); } proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; vector params; for (unsigned i = 0; i < num_bind; ++i) { params.push_back(parameter(binding[i])); @@ -2929,7 +2929,7 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const { proof * ast_manager::mk_def_axiom(expr * ax) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); } @@ -3067,7 +3067,7 @@ proof * ast_manager::mk_def_intro(expr * new_def) { proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; ptr_buffer args; args.append(num_proofs, (expr**) proofs); args.push_back(mk_oeq(n, def)); @@ -3100,7 +3100,7 @@ bool ast_manager::check_nnf_proof_parents(unsigned num_proofs, proof * const * p proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3110,7 +3110,7 @@ proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; check_nnf_proof_parents(num_proofs, proofs); ptr_buffer args; args.append(num_proofs, (expr**) proofs); @@ -3120,7 +3120,7 @@ proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; ptr_buffer args; args.append(num_proofs, (expr**) proofs); args.push_back(mk_oeq(s, t)); @@ -3129,7 +3129,7 @@ proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof proof * ast_manager::mk_skolemization(expr * q, expr * e) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; SASSERT(is_bool(q)); SASSERT(is_bool(e)); return mk_app(m_basic_family_id, PR_SKOLEMIZE, mk_oeq(q, e)); @@ -3137,7 +3137,7 @@ proof * ast_manager::mk_skolemization(expr * q, expr * e) { proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; ptr_buffer args; args.append(num_proofs, (expr**) proofs); args.push_back(mk_oeq(s, t)); @@ -3146,7 +3146,7 @@ proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof proof * ast_manager::mk_and_elim(proof * p, unsigned i) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; SASSERT(has_fact(p)); SASSERT(is_and(get_fact(p))); CTRACE("mk_and_elim", i >= to_app(get_fact(p))->get_num_args(), tout << "i: " << i << "\n" << mk_pp(get_fact(p), *this) << "\n";); @@ -3157,7 +3157,7 @@ proof * ast_manager::mk_and_elim(proof * p, unsigned i) { proof * ast_manager::mk_not_or_elim(proof * p, unsigned i) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; SASSERT(has_fact(p)); SASSERT(is_not(get_fact(p))); SASSERT(is_or(to_app(get_fact(p))->get_arg(0))); @@ -3180,7 +3180,7 @@ proof * ast_manager::mk_th_lemma( ) { if (proofs_disabled()) - return m_undef_proof; + return nullptr; ptr_buffer args; vector parameters; diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index f5f72674d..2abd6d467 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -351,7 +351,6 @@ void rewriter_tpl::process_app(app * t, frame & fr) { if (is_ground(def)) { m_r = def; if (ProofGen) { - SASSERT(def_pr); m_pr = m().mk_transitivity(m_pr, def_pr); } } @@ -510,7 +509,7 @@ void rewriter_tpl::process_quantifier(quantifier * q, frame & fr) { new_no_pats = q->get_no_patterns(); } if (ProofGen) { - quantifier * new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); + quantifier_ref new_q(m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body), m()); m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos)); m_r = new_q; proof_ref pr2(m()); From 861a0745c148ae5a775a7ea9f3de0ecd1828ddf6 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 6 Nov 2017 10:36:10 +0000 Subject: [PATCH 55/57] remove a few unneded mem allocations --- src/tactic/bv/bv_size_reduction_tactic.cpp | 6 +++--- src/tactic/bv/max_bv_sharing_tactic.cpp | 7 ++++--- src/tactic/core/propagate_values_tactic.cpp | 5 +++-- src/tactic/core/simplify_tactic.cpp | 6 +++--- src/tactic/smtlogics/qfufbv_tactic.cpp | 8 ++++---- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/tactic/bv/bv_size_reduction_tactic.cpp b/src/tactic/bv/bv_size_reduction_tactic.cpp index 9401f74c1..ec4c21fe8 100644 --- a/src/tactic/bv/bv_size_reduction_tactic.cpp +++ b/src/tactic/bv/bv_size_reduction_tactic.cpp @@ -399,8 +399,8 @@ void bv_size_reduction_tactic::operator()(goal_ref const & g, void bv_size_reduction_tactic::cleanup() { - imp * d = alloc(imp, m_imp->m); - std::swap(d, m_imp); - dealloc(d); + ast_manager & m = m_imp->m; + m_imp->~imp(); + new (m_imp) imp(m); } diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index b0affeb4b..becaed276 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -307,9 +307,10 @@ public: } virtual void cleanup() { - imp * d = alloc(imp, m_imp->m(), m_params); - std::swap(d, m_imp); - dealloc(d); + ast_manager & m = m_imp->m(); + params_ref p = std::move(m_params); + m_imp->~imp(); + new (m_imp) imp(m, p); } }; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 7baac0b99..607ecbd79 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -255,8 +255,9 @@ public: virtual void cleanup() { ast_manager & m = m_imp->m; - dealloc(m_imp); - m_imp = alloc(imp, m, m_params); + params_ref p = std::move(m_params); + m_imp->~imp(); + new (m_imp) imp(m, p); } }; diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index 9deff968e..de1fcc99c 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -111,9 +111,9 @@ void simplify_tactic::operator()(goal_ref const & in, void simplify_tactic::cleanup() { ast_manager & m = m_imp->m(); - imp * d = alloc(imp, m, m_params); - std::swap(d, m_imp); - dealloc(d); + params_ref p = std::move(m_params); + m_imp->~imp(); + new (m_imp) imp(m, p); } unsigned simplify_tactic::get_num_steps() const { diff --git a/src/tactic/smtlogics/qfufbv_tactic.cpp b/src/tactic/smtlogics/qfufbv_tactic.cpp index e89da3631..df2791a8f 100644 --- a/src/tactic/smtlogics/qfufbv_tactic.cpp +++ b/src/tactic/smtlogics/qfufbv_tactic.cpp @@ -70,8 +70,8 @@ public: const unsigned sz = g->size(); for (unsigned i = 0; i < sz; i++) flas.push_back(g->form(i)); scoped_ptr uffree_solver = setup_sat(); - scoped_ptr imp = alloc(lackr, m, m_p, m_st, flas, uffree_solver.get()); - const lbool o = imp->operator()(); + lackr imp(m, m_p, m_st, flas, uffree_solver.get()); + const lbool o = imp.operator()(); flas.reset(); // report result goal_ref resg(alloc(goal, *g, true)); @@ -79,8 +79,8 @@ public: if (o != l_undef) result.push_back(resg.get()); // report model if (g->models_enabled() && (o == l_true)) { - model_ref abstr_model = imp->get_model(); - mc = mk_qfufbv_ackr_model_converter(m, imp->get_info(), abstr_model); + model_ref abstr_model = imp.get_model(); + mc = mk_qfufbv_ackr_model_converter(m, imp.get_info(), abstr_model); } } From 9d3518736bda418f6a4a9b82d12cceaf83fee0b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 15:25:10 -0800 Subject: [PATCH 56/57] fix #889 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 8 +------- src/smt/asserted_formulas.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 7eae396ff..98c1bdfed 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1683,7 +1683,7 @@ ast * ast_manager::register_node_core(ast * n) { bool contains = m_ast_table.contains(n); CASSERT("nondet_bug", contains || slow_not_contains(n)); #endif - + #if 0 static unsigned counter = 0; counter++; @@ -1719,12 +1719,6 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); - static unsigned count = 0; - if (n->m_id == 404) { - ++count; - //if (count == 2) SASSERT(false); - } - TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); // increment reference counters diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index dd92f250a..56600266a 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -511,11 +511,14 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } - if (m.is_not(n, n1)) { - m_scoped_substitution.insert(n1, m.mk_false(), m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr); + proof_ref pr1(m); + if (m.is_not(n, n1)) { + pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr; + m_scoped_substitution.insert(n1, m.mk_false(), pr1); } else { - m_scoped_substitution.insert(n, m.mk_true(), m.proofs_enabled() ? m.mk_iff_true(pr) : nullptr); + pr1 = m.proofs_enabled() ? m.mk_iff_true(pr) : nullptr; + m_scoped_substitution.insert(n, m.mk_true(), pr1); } } From 3350f32e1f2c01c9df63b7d71899796a18ce2272 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Nov 2017 16:00:16 -0800 Subject: [PATCH 57/57] fix #877 by bypassing exception generation during label collection Signed-off-by: Nikolaj Bjorner --- src/duality/duality_rpfp.cpp | 94 +++++------------------------------- 1 file changed, 13 insertions(+), 81 deletions(-) diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index c9ad8fd56..5dc2283ae 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -1575,6 +1575,7 @@ namespace Duality { */ int RPFP::SubtermTruth(hash_map &memo, const Term &f) { + TRACE("duality", tout << f << "\n";); if (memo.find(f) != memo.end()) { return memo[f]; } @@ -1657,83 +1658,6 @@ namespace Duality { ands and, or, not. Returns result in memo. */ -#if 0 - int RPFP::GetLabelsRec(hash_map *memo, const Term &f, std::vector &labels, bool labpos){ - if(memo[labpos].find(f) != memo[labpos].end()){ - return memo[labpos][f]; - } - int res; - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies){ - res = GetLabelsRec(memo,f.arg(1) || !f.arg(0), labels, labpos); - goto done; - } - if(k == And) { - res = 1; - for(int i = 0; i < nargs; i++){ - int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); - if(ar == 0){ - res = 0; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Or) { - res = 0; - for(int i = 0; i < nargs; i++){ - int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); - if(ar == 1){ - res = 1; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Not) { - int ar = GetLabelsRec(memo,f.arg(0), labels, !labpos); - res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); - goto done; - } - } - { - bool pos; std::vector names; - if(f.is_label(pos,names)){ - res = GetLabelsRec(memo,f.arg(0), labels, labpos); - if(pos == labpos && res == (pos ? 1 : 0)) - for(unsigned i = 0; i < names.size(); i++) - labels.push_back(names[i]); - goto done; - } - } - { - expr bv = dualModel.eval(f); - if(bv.is_app() && bv.decl().get_decl_kind() == Equal && - bv.arg(0).is_array()){ - bv = EvalArrayEquality(bv); - } - // Hack!!!! array equalities can occur negatively! - if(bv.is_app() && bv.decl().get_decl_kind() == Not && - bv.arg(0).decl().get_decl_kind() == Equal && - bv.arg(0).arg(0).is_array()){ - bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); - } - if(eq(bv,ctx.bool_val(true))) - res = 1; - else if(eq(bv,ctx.bool_val(false))) - res = 0; - else - res = 2; - } - done: - memo[labpos][f] = res; - return res; - } -#endif void RPFP::GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, hash_set *done, bool truth) { @@ -1748,8 +1672,13 @@ namespace Duality { } if (k == Iff) { int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) - throw "disaster in GetLabelsRec"; + if (b == 2) { + goto done; + // bypass error + std::ostringstream os; + os << "disaster in SubtermTruth processing " << f; + throw default_exception(os.str()); + } GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b); goto done; } @@ -1825,8 +1754,11 @@ namespace Duality { } if (k == Iff) { int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) - throw "disaster in ImplicantRed"; + if (b == 2) { + std::ostringstream os; + os << "disaster in SubtermTruth processing " << f; + throw default_exception(os.str()); + } ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares); goto done; }