From 9cd974e3343b83491200071442537d7765f48ad7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Sep 2017 09:40:35 -0700 Subject: [PATCH 01/67] remove display Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 63f1badb7..8782cb462 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -724,8 +724,6 @@ namespace sat { pop_to_base_level(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(scope_lvl() == 0); - SASSERT(m_config.m_dimacs_display); - std::cout << "display dimacs: " << m_config.m_dimacs_display << "\n"; if (m_config.m_dimacs_display) { display_dimacs(std::cout); for (unsigned i = 0; i < num_lits; ++lits) { From f179d49f4f4ac90e9515f42ee690426c5a67fa52 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Sep 2017 10:58:39 -0700 Subject: [PATCH 02/67] check for eof, based on testing garbled repro from #1267 Signed-off-by: Nikolaj Bjorner --- src/parsers/smt2/smt2scanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index c1cc40b2b..9a9e69b67 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -124,7 +124,7 @@ namespace smt2 { next(); bool is_float = false; - while (true) { + while (!m_at_eof) { char c = curr(); if ('0' <= c && c <= '9') { m_number = rational(10)*m_number + rational(c - '0'); From c8a67abdd70550cbab22bafd259a21f68433da7c Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Mon, 25 Sep 2017 14:33:20 -0700 Subject: [PATCH 03/67] fixing issue [1269] --- src/interp/iz3mgr.cpp | 29 +++++++++++++++++++++++++++++ src/interp/iz3mgr.h | 6 ++++++ src/interp/iz3proof_itp.cpp | 4 ++-- src/interp/iz3translate.cpp | 5 +++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp index 306807f1f..7314403b0 100755 --- a/src/interp/iz3mgr.cpp +++ b/src/interp/iz3mgr.cpp @@ -33,9 +33,11 @@ #include #include #include +#include #include "ast/expr_abstract.h" #include "util/params.h" +#include "ast/used_vars.h" using namespace stl_ext; @@ -938,3 +940,30 @@ void iz3mgr::get_bound_substitutes(stl_ext::hash_map &memo, const ast } #endif + +unsigned iz3mgr::num_free_variables(const ast &e){ + used_vars uv; + uv(to_expr(e.raw())); + return uv.get_num_vars(); +} + +iz3mgr::ast iz3mgr::close_universally (ast e){ + used_vars uv; + uv(to_expr(e.raw())); + std::vector bvs; + stl_ext::hash_map subst_memo; + for (unsigned i = 0; i < uv.get_max_found_var_idx_plus_1(); i++){ + if (uv.get(i)) { + std::ostringstream os; + os << "%%" << i; + ast c = make_var(os.str(),uv.get(i)); + ast v = cook(m().mk_var(i,uv.get(i))); + subst_memo[v] = c; + bvs.push_back(c); + } + } + e = subst(subst_memo,e); + for (unsigned i = 0; i < bvs.size(); i++) + e = apply_quant(Forall,bvs[i],e); + return e; +} diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index e6e08f84d..6ca8fae34 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -661,6 +661,12 @@ class iz3mgr { ast apply_quant(opr quantifier, ast var, ast e); + // Universally quantify all the free variables in a formula. + // Makes up names for the quntifiers. + + ast close_universally (ast e); + + unsigned num_free_variables(const ast &e); /** For debugging */ void show(ast); diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index eb7f8e325..fc9d0fac6 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -2968,9 +2968,9 @@ class iz3proof_itp_impl : public iz3proof_itp { ast interpolate(const node &pf){ // proof of false must be a formula, with quantified symbols #ifndef BOGUS_QUANTS - return add_quants(z3_simplify(pf)); + return close_universally(add_quants(z3_simplify(pf))); #else - return z3_simplify(pf); + return close_universally(z3_simplify(pf)); #endif } diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index ebbee46ca..c59dd0178 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -234,6 +234,11 @@ public: } } + // if(!range_is_empty(rng)){ + // if (num_free_variables(con) > 0) + // rng = range_empty(); + // } + if(res == INT_MAX){ if(range_is_empty(rng)) res = -1; From 6450ee33c58a9dc5e86b7a7b852af46277ce16d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 08:25:48 -0700 Subject: [PATCH 04/67] disregard model validation when source expression contains uninterpreted theory functions Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 260d49174..3f34f3128 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1763,7 +1763,7 @@ void cmd_context::validate_model() { continue; } try { - for_each_expr(contains_underspecified, r); + for_each_expr(contains_underspecified, a); } catch (contains_underspecified_op_proc::found) { continue; From 2229a2fc1b07e733bbb69bd3f997cfd259134ca7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Sep 2017 08:43:31 -0700 Subject: [PATCH 05/67] model validation update take 2 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 3f34f3128..b2a4fc47f 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1764,6 +1764,7 @@ void cmd_context::validate_model() { } try { for_each_expr(contains_underspecified, a); + for_each_expr(contains_underspecified, r); } catch (contains_underspecified_op_proc::found) { continue; From f07b89df867b29f3dc16633a94f5e204c97fae90 Mon Sep 17 00:00:00 2001 From: Max ulidtko Date: Tue, 26 Sep 2017 17:27:47 +0300 Subject: [PATCH 06/67] fix pydoc part of `make api_docs` --- doc/mk_api_doc.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index 234dd670c..d7e8e2fb1 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -288,8 +288,21 @@ try: # Put z3py at the beginning of the search path to try to avoid picking up # an installed copy of Z3py. sys.path.insert(0, os.path.dirname(Z3PY_PACKAGE_PATH)) - pydoc.writedoc('z3') - shutil.move('z3.html', os.path.join(OUTPUT_DIRECTORY, 'html', 'z3.html')) + for modulename in ( + 'z3', + 'z3.z3consts', + 'z3.z3core', + 'z3.z3num', + 'z3.z3poly', + 'z3.z3printer', + 'z3.z3rcf', + 'z3.z3types', + 'z3.z3util', + ): + pydoc.writedoc(modulename) + doc = modulename + '.html' + shutil.move(doc, os.path.join(OUTPUT_DIRECTORY, 'html', doc)) + print("Generated pydoc Z3Py documentation.") if ML_ENABLED: From ce6e26043af3ec3f1e857ab1cfacd6158a472589 Mon Sep 17 00:00:00 2001 From: Max ulidtko Date: Wed, 27 Sep 2017 14:03:38 +0300 Subject: [PATCH 07/67] fix Python API doxygen (`make api_docs`) --- doc/mk_api_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index d7e8e2fb1..ab4d32d39 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -188,7 +188,7 @@ try: if Z3PY_ENABLED: print("Z3Py documentation enabled") - doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3.py' + doxygen_config_substitutions['PYTHON_API_FILES'] = 'z3*.py' else: print("Z3Py documentation disabled") doxygen_config_substitutions['PYTHON_API_FILES'] = '' From 9a464dded4a0208d29ff604cb91ccf0fbd9e665b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 27 Sep 2017 14:22:59 +0100 Subject: [PATCH 08/67] Removed -std=c++11 from OCaml stubs build command. Fixes #1263. --- scripts/mk_util.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 24f22d8ee..6f3052f6e 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1913,7 +1913,11 @@ class MLComponent(Component): src_dir = self.to_src_dir mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) api_src = get_component(API_COMPONENT).to_src_dir - out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it. + # remove /GL and -std=c++11; the ocaml tools don't like them. + if IS_WINDOWS: + out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') + else: + out.write('CXXFLAGS_OCAML=$(subst -std=c++11,,$(CXXFLAGS))\n') if IS_WINDOWS: prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') From 8ff8c6433b9c377bae84c5c72084eefa3fbded3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Sep 2017 10:15:27 -0700 Subject: [PATCH 09/67] fix #1277 fix #1278 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 6 ++++++ src/smt/theory_arith_nl.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index b2a4fc47f..95c030687 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -870,6 +870,12 @@ void cmd_context::insert_rec_fun(func_decl* f, expr_ref_vector const& binding, s lhs = m().mk_app(f, binding.size(), binding.c_ptr()); eq = m().mk_eq(lhs, e); if (!ids.empty()) { + if (is_var(e)) { + ptr_vector domain; + for (expr* b : binding) domain.push_back(m().get_sort(b)); + insert_macro(f->get_name(), domain.size(), domain.c_ptr(), e); + return; + } if (!is_app(e)) { throw cmd_exception("Z3 only supports recursive definitions that are proper terms (not binders or variables)"); } diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index a04c34706..230b6de77 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -780,7 +780,7 @@ namespace smt { of a non linear monomial that is not satisfied by the current assignment. if v >= l, then create the case split v >= l+1 else v <= u, then create the case split v <= u-1 - else do nothing and return false. + else create the bound v = 0 and case split on it. */ template bool theory_arith::branch_nl_int_var(theory_var v) { From bec60f763bbe8daf87413088f19a4b7c23ba7e5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Sep 2017 12:35:36 -0700 Subject: [PATCH 10/67] add diagnostics to DDNF and fix #1268 Signed-off-by: Nikolaj Bjorner --- src/muz/ddnf/ddnf.cpp | 21 ++++++++++++++++----- src/test/ddnf.cpp | 4 ++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/muz/ddnf/ddnf.cpp b/src/muz/ddnf/ddnf.cpp index 0e2f6b35f..da1f5392b 100644 --- a/src/muz/ddnf/ddnf.cpp +++ b/src/muz/ddnf/ddnf.cpp @@ -192,10 +192,15 @@ namespace datalog { for (unsigned i = 0; i < new_tbvs.size(); ++i) { tbv const& nt = *new_tbvs[i]; IF_VERBOSE(10, m_tbv.display(verbose_stream() << "insert: ", nt); verbose_stream() << "\n";); - if (contains(nt)) continue; - ddnf_node* n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); - m_noderefs.push_back(n); - m_nodes.insert(n); + ddnf_node* n; + if (contains(nt)) { + n = find(nt); + } + else { + n = alloc(ddnf_node, *this, m_tbv, nt, m_noderefs.size()); + m_noderefs.push_back(n); + m_nodes.insert(n); + } insert(*m_root, n, new_tbvs); } return find(t); @@ -275,13 +280,17 @@ namespace datalog { void insert(ddnf_node& root, ddnf_node* new_n, ptr_vector& new_intersections) { tbv const& new_tbv = new_n->get_tbv(); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "root: ", root.get_tbv()); + m_tbv.display(verbose_stream() << " new node ", new_tbv); verbose_stream() << "\n";); SASSERT(m_tbv.contains(root.get_tbv(), new_tbv)); - if (&root == new_n) return; + if (m_eq(&root, new_n)) return; ++m_stats.m_num_inserts; bool inserted = false; for (unsigned i = 0; i < root.num_children(); ++i) { ddnf_node& child = *(root[i]); ++m_stats.m_num_comparisons; + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "child ", child.get_tbv()); + verbose_stream() << " contains: " << m_tbv.contains(child.get_tbv(), new_tbv) << "\n";); if (m_tbv.contains(child.get_tbv(), new_tbv)) { inserted = true; insert(child, new_n, new_intersections); @@ -299,11 +308,13 @@ namespace datalog { // checking for subset if (m_tbv.contains(new_tbv, child.get_tbv())) { subset_children.push_back(&child); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "contains child", child.get_tbv()); verbose_stream() << "\n";); ++m_stats.m_num_comparisons; } else if (m_tbv.intersect(child.get_tbv(), new_tbv, *intr)) { // this means there is a non-full intersection new_intersections.push_back(intr); + IF_VERBOSE(10, m_tbv.display(verbose_stream() << "intersect child ", child.get_tbv()); verbose_stream() << "\n";); intr = m_tbv.allocate(); m_stats.m_num_comparisons += 2; } diff --git a/src/test/ddnf.cpp b/src/test/ddnf.cpp index 09f1a4cf9..c9eb6aa08 100644 --- a/src/test/ddnf.cpp +++ b/src/test/ddnf.cpp @@ -214,6 +214,10 @@ void tst_ddnf1() { ddnf.insert(*tX1); ddnf.insert(*t1X); ddnf.display(std::cout); + tbvm.deallocate(tXX); + tbvm.deallocate(t1X); + tbvm.deallocate(tX1); + tbvm.deallocate(t11); } From 05428314be0a3b7bd6b682d0467efa0fe892c9d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Oct 2017 15:13:43 -0700 Subject: [PATCH 11/67] fix #1276 related crashes for re-sumption after cancellation Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/maximize_ac_sharing.cpp | 4 ---- src/smt/asserted_formulas.cpp | 7 ++++--- src/smt/smt_context.cpp | 11 ++++++++++- src/util/rlimit.cpp | 5 +++-- src/util/rlimit.h | 15 ++++++++++++++- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/ast/rewriter/maximize_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp index b560132db..d7e8df7a2 100644 --- a/src/ast/rewriter/maximize_ac_sharing.cpp +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -151,11 +151,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) { } void maximize_ac_sharing::reset() { - restore_entries(0); - m_entries.reset(); m_cache.reset(); - m_region.reset(); - m_scopes.reset(); } void maximize_bv_sharing::init_core() { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index c52ad851c..11cc846b8 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -170,7 +170,7 @@ void asserted_formulas::get_assertions(ptr_vector & result) const { void asserted_formulas::push_scope() { SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); - TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "before push: " << m_scopes.size() << "\n";); m_scoped_substitution.push(); m_scopes.push_back(scope()); scope & s = m_scopes.back(); @@ -181,10 +181,11 @@ void asserted_formulas::push_scope() { m_bv_sharing.push_scope(); m_macro_manager.push_scope(); commit(); + TRACE("asserted_formulas_scopes", tout << "after push: " << m_scopes.size() << "\n";); } void asserted_formulas::pop_scope(unsigned num_scopes) { - TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << " of " << m_scopes.size() << "\n";); m_bv_sharing.pop_scope(num_scopes); m_macro_manager.pop_scope(num_scopes); unsigned new_lvl = m_scopes.size() - num_scopes; @@ -196,7 +197,7 @@ void asserted_formulas::pop_scope(unsigned num_scopes) { m_qhead = s.m_formulas_lim; m_scopes.shrink(new_lvl); flush_cache(); - TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n";); } void asserted_formulas::reset() { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 901f4b5ac..ac7b1f44b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -487,6 +487,7 @@ namespace smt { */ void context::add_eq(enode * n1, enode * n2, eq_justification js) { unsigned old_trail_size = m_trail_stack.size(); + scoped_suspend_rlimit _suspend_cancel(m_manager.limit()); try { TRACE("add_eq", tout << "assigning: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); @@ -541,10 +542,14 @@ namespace smt { mark_as_relevant(r1); } + TRACE("add_eq", tout << "to trail\n";); + push_trail(add_eq_trail(r1, n1, r2->get_num_parents())); + TRACE("add_eq", tout << "qmanager add_eq\n";); m_qmanager->add_eq_eh(r1, r2); + TRACE("add_eq", tout << "merge theory_vars\n";); merge_theory_vars(n2, n1, js); // 'Proof' tree @@ -577,6 +582,7 @@ namespace smt { #endif + TRACE("add_eq", tout << "remove_parents_from_cg_table\n";); remove_parents_from_cg_table(r1); enode * curr = r1; @@ -588,8 +594,10 @@ namespace smt { SASSERT(r1->get_root() == r2); + TRACE("add_eq", tout << "reinsert_parents_into_cg_table\n";); reinsert_parents_into_cg_table(r1, r2, n1, n2, js); + TRACE("add_eq", tout << "propagate_bool_enode_assignment\n";); if (n2->is_bool()) propagate_bool_enode_assignment(r1, r2, n1, n2); @@ -604,6 +612,7 @@ namespace smt { catch (...) { // Restore trail size since procedure was interrupted in the middle. // If the add_eq_trail remains on the trail stack, then Z3 may crash when the destructor is invoked. + TRACE("add_eq", tout << "add_eq interrupted. This is unsafe " << m_manager.limit().get_cancel_flag() << "\n";); m_trail_stack.shrink(old_trail_size); throw; } @@ -972,7 +981,7 @@ namespace smt { enode * parent = *it; if (parent->is_cgc_enabled()) { TRACE("add_eq_parents", tout << "removing: #" << parent->get_owner_id() << "\n";); - CTRACE("add_eq", !parent->is_cgr(), + CTRACE("add_eq", !parent->is_cgr() || !m_cg_table.contains_ptr(parent), tout << "old num_parents: " << r2_num_parents << ", num_parents: " << r2->m_parents.size() << ", parent: #" << parent->get_owner_id() << ", parents: \n"; for (unsigned i = 0; i < r2->m_parents.size(); i++) { diff --git a/src/util/rlimit.cpp b/src/util/rlimit.cpp index f3f45c654..e625cab95 100644 --- a/src/util/rlimit.cpp +++ b/src/util/rlimit.cpp @@ -21,6 +21,7 @@ Revision History: reslimit::reslimit(): m_cancel(0), + m_suspend(false), m_count(0), m_limit(0) { } @@ -31,12 +32,12 @@ uint64 reslimit::count() const { bool reslimit::inc() { ++m_count; - return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); + return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; } bool reslimit::inc(unsigned offset) { m_count += offset; - return m_cancel == 0 && (m_limit == 0 || m_count <= m_limit); + return (m_cancel == 0 && (m_limit == 0 || m_count <= m_limit)) || m_suspend; } void reslimit::push(unsigned delta_limit) { diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 3b278d132..0c81f9449 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -23,12 +23,14 @@ Revision History: class reslimit { volatile unsigned m_cancel; + bool m_suspend; uint64 m_count; uint64 m_limit; svector m_limits; ptr_vector m_children; void set_cancel(unsigned f); + friend class scoped_suspend_rlimit; public: reslimit(); @@ -42,7 +44,7 @@ public: uint64 count() const; - bool get_cancel_flag() const { return m_cancel > 0; } + bool get_cancel_flag() const { return m_cancel > 0 && !m_suspend; } char const* get_cancel_msg() const; void cancel(); void reset_cancel(); @@ -61,6 +63,17 @@ public: }; +class scoped_suspend_rlimit { + reslimit & m_limit; +public: + scoped_suspend_rlimit(reslimit& r): m_limit(r) { + r.m_suspend = true; + } + ~scoped_suspend_rlimit() { + m_limit.m_suspend = false; + } +}; + struct scoped_limits { reslimit& m_limit; unsigned m_sz; From e0e23975665e4344f853c8f9a51ab34ff50e5f3c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Oct 2017 19:40:30 -0700 Subject: [PATCH 12/67] missing setup datatypes for QF_DT Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_generator.cpp | 18 ++++++++++-------- src/smt/smt_setup.cpp | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 5848fac62..df6865f1e 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -54,7 +54,7 @@ namespace smt { ptr_vector::const_iterator it = m_context->begin_theories(); ptr_vector::const_iterator end = m_context->end_theories(); for (; it != end; ++it) { - TRACE("model_generator_bug", tout << "init_model for theory: " << (*it)->get_name() << "\n";); + TRACE("model", tout << "init_model for theory: " << (*it)->get_name() << "\n";); (*it)->init_model(*this); } } @@ -91,7 +91,7 @@ namespace smt { sort * s = m_manager.get_sort(r->get_owner()); model_value_proc * proc = 0; if (m_manager.is_bool(s)) { - CTRACE("func_interp_bug", m_context->get_assignment(r) == l_undef, + CTRACE("model", m_context->get_assignment(r) == l_undef, tout << mk_pp(r->get_owner(), m_manager) << "\n";); SASSERT(m_context->get_assignment(r) != l_undef); if (m_context->get_assignment(r) == l_true) @@ -108,7 +108,7 @@ namespace smt { SASSERT(proc); } else { - TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); + TRACE("model", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); proc = alloc(fresh_value_proc, mk_extra_fresh_value(m_manager.get_sort(r->get_owner()))); } } @@ -130,7 +130,7 @@ namespace smt { if (!m_manager.is_model_value(n)) { sort * s = m_manager.get_sort(r->get_owner()); n = m_model->get_fresh_value(s); - CTRACE("model_generator_bug", n == 0, + CTRACE("model", n == 0, tout << mk_pp(r->get_owner(), m_manager) << "\nsort:\n" << mk_pp(s, m_manager) << "\n"; tout << "is_finite: " << m_model->is_finite(s) << "\n";); } @@ -406,9 +406,11 @@ namespace smt { */ bool model_generator::include_func_interp(func_decl * f) const { family_id fid = f->get_family_id(); + TRACE("model", tout << f->get_name() << " " << fid << "\n";); if (fid == null_family_id) return !m_hidden_ufs.contains(f); if (fid == m_manager.get_basic_family_id()) return false; theory * th = m_context->get_theory(fid); + TRACE("model", tout << th << "\n";); if (!th) return true; return th->include_func_interp(f); } @@ -443,7 +445,7 @@ namespace smt { SASSERT(m_model->has_interpretation(f)); SASSERT(m_model->get_func_interp(f) == fi); // The entry must be new because n->get_cg() == n - TRACE("func_interp_bug", + TRACE("model", tout << "insert new entry for:\n" << mk_ismt2_pp(n->get_owner(), m_manager) << "\nargs: "; for (unsigned i = 0; i < num_args; i++) { tout << "#" << n->get_arg(i)->get_owner_id() << " "; @@ -507,20 +509,20 @@ namespace smt { void model_generator::register_macros() { unsigned num = m_context->get_num_macros(); - TRACE("register_macros", tout << "num. macros: " << num << "\n";); + TRACE("model", tout << "num. macros: " << num << "\n";); expr_ref v(m_manager); for (unsigned i = 0; i < num; i++) { func_decl * f = m_context->get_macro_interpretation(i, v); func_interp * fi = alloc(func_interp, m_manager, f->get_arity()); fi->set_else(v); - TRACE("register_macros", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); + TRACE("model", tout << f->get_name() << "\n" << mk_pp(v, m_manager) << "\n";); m_model->register_decl(f, fi); } } proto_model * model_generator::mk_model() { SASSERT(!m_model); - TRACE("func_interp_bug", m_context->display(tout);); + TRACE("model", m_context->display(tout);); init_model(); register_existing_model_values(); mk_bool_model(); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 56b5d541a..631805b4d 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -216,6 +216,7 @@ namespace smt { void setup::setup_QF_DT() { setup_QF_UF(); + setup_datatypes(); } void setup::setup_QF_BVRE() { From 6c7a82edceef5e96476b2e80433d4b1a1a61b103 Mon Sep 17 00:00:00 2001 From: Miguel Angelo Da Terra Neves Date: Mon, 2 Oct 2017 09:20:59 -0700 Subject: [PATCH 13/67] update to _get_args to convert arguments from AstVector to a python list Signed-off-by: Miguel Angelo Da Terra Neves --- src/api/python/z3/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 39af03190..a521c5169 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -120,7 +120,7 @@ def _get_args(args): try: if len(args) == 1 and (isinstance(args[0], tuple) or isinstance(args[0], list)): return args[0] - elif len(args) == 1 and isinstance(args[0], set): + elif len(args) == 1 and (isinstance(args[0], set) or isinstance(args[0], AstVector)): return [arg for arg in args[0]] else: return args From 2828126b725362ee08daf0cf8a774d0b09cc3dcb Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 3 Oct 2017 10:20:49 -0700 Subject: [PATCH 14/67] add cancellation checks Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.h | 2 + src/util/lp/lp_primal_core_solver_tableau.h | 45 ++++++++++++--------- src/util/lp/lp_settings.h | 3 +- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 1ed30bd70..6d2cbea7d 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -417,6 +417,8 @@ public: for (unsigned i : m_rows_with_changed_bounds.m_index) { calculate_implied_bounds_for_row(i, bp); + if (settings().get_cancel_flag()) + return; } m_rows_with_changed_bounds.clear(); if (!use_tableau()) { diff --git a/src/util/lp/lp_primal_core_solver_tableau.h b/src/util/lp/lp_primal_core_solver_tableau.h index 5c7d4d2c2..d2b8c1a26 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.h +++ b/src/util/lp/lp_primal_core_solver_tableau.h @@ -176,25 +176,34 @@ unsigned lp_primal_core_solver::solve_with_tableau() { default: break; // do nothing } - } while (this->get_status() != FLOATING_POINT_ERROR - && - this->get_status() != UNBOUNDED - && - this->get_status() != OPTIMAL - && - this->get_status() != INFEASIBLE - && - this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements - && - this->total_iterations() <= this->m_settings.max_total_number_of_iterations - && - !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); + } while (this->get_status() != FLOATING_POINT_ERROR + && + this->get_status() != UNBOUNDED + && + this->get_status() != OPTIMAL + && + this->get_status() != INFEASIBLE + && + this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements + && + this->total_iterations() <= this->m_settings.max_total_number_of_iterations + && + !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) + && + m_settings.get_cancel_flag() == false); + + if (m_settings.get_cancel_flag()) { + this->set_status(CANCELLED); + } - SASSERT(this->get_status() == FLOATING_POINT_ERROR - || - this->current_x_is_feasible() == false - || - this->calc_current_x_is_feasible_include_non_basis()); + SASSERT( + this->get_status() == FLOATING_POINT_ERROR + || + this->get_status() == CANCELLED + || + this->current_x_is_feasible() == false + || + this->calc_current_x_is_feasible_include_non_basis()); return this->total_iterations(); } diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 70a9f1504..a7e6e2665 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -61,7 +61,8 @@ enum lp_status { TIME_EXHAUSTED, ITERATIONS_EXHAUSTED, EMPTY, - UNSTABLE + UNSTABLE, + CANCELLED }; // when the ratio of the vector lenth to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only From fd3d785a5b41715a5a1c61ea03038c550483030e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 4 Oct 2017 14:49:45 -0700 Subject: [PATCH 15/67] add this-> Signed-off-by: Lev Nachmanson --- src/util/lp/lp_primal_core_solver_tableau.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/lp/lp_primal_core_solver_tableau.h b/src/util/lp/lp_primal_core_solver_tableau.h index d2b8c1a26..0c56f0ab9 100644 --- a/src/util/lp/lp_primal_core_solver_tableau.h +++ b/src/util/lp/lp_primal_core_solver_tableau.h @@ -190,10 +190,10 @@ unsigned lp_primal_core_solver::solve_with_tableau() { && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) && - m_settings.get_cancel_flag() == false); + this->m_settings.get_cancel_flag() == false); - if (m_settings.get_cancel_flag()) { - this->set_status(CANCELLED); + if (this->m_settings.get_cancel_flag()) { + this->set_status(CANCELLED); } SASSERT( From 110d558ee4262721f3ab2c999d789eaf84ac15d6 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 5 Oct 2017 08:53:12 +0100 Subject: [PATCH 16/67] dom_simplify_tactic: micro opt --- src/tactic/core/dom_simplify_tactic.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 595f8f7c6..d4a3031cd 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -225,9 +225,8 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { } else { expr_dominators::tree_t const& t = m_dominators.get_tree(); - if (t.contains(e)) { - ptr_vector const& children = t[e]; - for (expr * child : children) { + if (auto children = t.find_core(e)) { + for (expr * child : children->get_data().m_value) { simplify(child); } } From 53fc6ac11b25593e3827c943f5d61ce9f28da7ca Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 5 Oct 2017 14:27:56 +0100 Subject: [PATCH 17/67] [TravisCI] Refactor as many CI default options as possible so that the Docker and "TravisCI macOS" builds share most of the same defaults by sourcing the `ci_defaults.sh` file. --- contrib/ci/Dockerfiles/z3_build.Dockerfile | 50 ++++++++--------- contrib/ci/scripts/ci_defaults.sh | 54 +++++++++++++++++++ .../ci/scripts/travis_ci_linux_entry_point.sh | 4 +- .../ci/scripts/travis_ci_osx_entry_point.sh | 30 ++--------- 4 files changed, 86 insertions(+), 52 deletions(-) create mode 100644 contrib/ci/scripts/ci_defaults.sh diff --git a/contrib/ci/Dockerfiles/z3_build.Dockerfile b/contrib/ci/Dockerfiles/z3_build.Dockerfile index 2d16d5394..5f7608cf4 100644 --- a/contrib/ci/Dockerfiles/z3_build.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_build.Dockerfile @@ -2,34 +2,33 @@ ARG DOCKER_IMAGE_BASE FROM ${DOCKER_IMAGE_BASE} -# Specify defaults. This can be changed when invoking +# Build arguments. This can be changed when invoking # `docker build`. -ARG ASAN_BUILD=0 -ARG BUILD_DOCS=0 -ARG CC=gcc -ARG CXX=g++ -ARG DOTNET_BINDINGS=1 -ARG JAVA_BINDINGS=1 -ARG NO_SUPPRESS_OUTPUT=0 -ARG PYTHON_BINDINGS=1 -ARG PYTHON_EXECUTABLE=/usr/bin/python2.7 -ARG RUN_SYSTEM_TESTS=1 -ARG RUN_UNIT_TESTS=1 -ARG TARGET_ARCH=x86_64 -ARG TEST_INSTALL=1 -ARG UBSAN_BUILD=0 -ARG USE_LIBGMP=0 -ARG USE_LTO=0 -ARG USE_OPENMP=1 +ARG ASAN_BUILD +ARG BUILD_DOCS +ARG CC +ARG CXX +ARG DOTNET_BINDINGS +ARG JAVA_BINDINGS +ARG NO_SUPPRESS_OUTPUT +ARG PYTHON_BINDINGS +ARG PYTHON_EXECUTABLE +ARG RUN_SYSTEM_TESTS +ARG RUN_UNIT_TESTS +ARG TARGET_ARCH +ARG TEST_INSTALL +ARG UBSAN_BUILD +ARG USE_LIBGMP +ARG USE_LTO +ARG USE_OPENMP ARG Z3_SRC_DIR=/home/user/z3_src -ARG Z3_BUILD_TYPE=RelWithDebInfo -ARG Z3_CMAKE_GENERATOR=Ninja -ARG Z3_INSTALL_PREFIX=/usr -ARG Z3_STATIC_BUILD=0 -# Blank default indicates use latest. +ARG Z3_BUILD_TYPE +ARG Z3_CMAKE_GENERATOR +ARG Z3_INSTALL_PREFIX +ARG Z3_STATIC_BUILD ARG Z3_SYSTEM_TEST_GIT_REVISION -ARG Z3_WARNINGS_AS_ERRORS=SERIOUS_ONLY -ARG Z3_VERBOSE_BUILD_OUTPUT=0 +ARG Z3_WARNINGS_AS_ERRORS +ARG Z3_VERBOSE_BUILD_OUTPUT ENV \ ASAN_BUILD=${ASAN_BUILD} \ @@ -74,6 +73,7 @@ ADD *.txt *.md RELEASE_NOTES ${Z3_SRC_DIR}/ ADD \ /contrib/ci/scripts/build_z3_cmake.sh \ + /contrib/ci/scripts/ci_defaults.sh \ /contrib/ci/scripts/set_compiler_flags.sh \ /contrib/ci/scripts/set_generator_args.sh \ ${Z3_SRC_DIR}/contrib/ci/scripts/ diff --git a/contrib/ci/scripts/ci_defaults.sh b/contrib/ci/scripts/ci_defaults.sh new file mode 100644 index 000000000..354ea95b7 --- /dev/null +++ b/contrib/ci/scripts/ci_defaults.sh @@ -0,0 +1,54 @@ +# This file should be sourced by other scripts +# and not executed directly + +# Set CI build defaults + +export ASAN_BUILD="${ASAN_BUILD:-0}" +export BUILD_DOCS="${BUILD_DOCS:-0}" +export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}" +export JAVA_BINDINGS="${JAVA_BINDINGS:-1}" +export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}" +export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}" +export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}" +export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" +export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}" +export TARGET_ARCH="${TARGET_ARCH:-x86_64}" +export TEST_INSTALL="${TEST_INSTALL:-1}" +export UBSAN_BUILD="${UBSAN_BUILD:-0}" +export USE_LIBGMP="${USE_LIBGMP:-0}" +export USE_LTO="${USE_LTO:-0}" +export USE_OPENMP="${USE_OPENMP:-1}" + +export Z3_BUILD_TYPE="${Z3_BUILD_TYPE:-RelWithDebInfo}" +export Z3_CMAKE_GENERATOR="${Z3_CMAKE_GENERATOR:-Ninja}" +export Z3_STATIC_BUILD="${Z3_STATIC_BUILD:-0}" +# Default is blank which means get latest revision +export Z3_SYSTEM_TEST_GIT_REVISION="${Z3_SYSTEM_TEST_GIT_REVISION:-}" +export Z3_WARNINGS_AS_ERRORS="${Z3_WARNINGS_AS_ERRORS:-SERIOUS_ONLY}" +export Z3_VERBOSE_BUILD_OUTPUT="${Z3_VERBOSE_BUILD_OUTPUT:-0}" + +# Platform specific defaults +PLATFORM="$(uname -s)" +case "${PLATFORM}" in + Linux*) + export C_COMPILER="${C_COMPILER:-gcc}" + export CXX_COMPILER="${CXX_COMPILER:-g++}" + export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr}" + ;; + Darwin*) + export C_COMPILER="${C_COMPILER:-clang}" + export CXX_COMPILER="${CXX_COMPILER:-clang++}" + export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr/local}" + ;; + *) + echo "Unknown platform \"${PLATFORM}\"" + exit 1 + ;; +esac +unset PLATFORM + +# NOTE: The following variables are not set here because +# they are specific to the CI implementation +# Z3_SRC_DIR +# Z3_BUILD_DIR +# Z3_SYSTEM_TEST_DIR diff --git a/contrib/ci/scripts/travis_ci_linux_entry_point.sh b/contrib/ci/scripts/travis_ci_linux_entry_point.sh index 84b2dd400..c0f856faa 100755 --- a/contrib/ci/scripts/travis_ci_linux_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_linux_entry_point.sh @@ -11,13 +11,15 @@ DOCKER_FILE_DIR="$(cd ${SCRIPT_DIR}/../Dockerfiles; echo $PWD)" : ${LINUX_BASE?"LINUX_BASE must be specified"} - # Sanity check. Current working directory should be repo root if [ ! -f "./README.md" ]; then echo "Current working directory should be repo root" exit 1 fi +# Get defaults +source "${SCRIPT_DIR}/ci_defaults.sh" + BUILD_OPTS=() # Override options if they have been provided. # Otherwise the defaults in the Docker file will be used diff --git a/contrib/ci/scripts/travis_ci_osx_entry_point.sh b/contrib/ci/scripts/travis_ci_osx_entry_point.sh index c5e8b4c02..7dd566877 100755 --- a/contrib/ci/scripts/travis_ci_osx_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_osx_entry_point.sh @@ -6,26 +6,8 @@ set -x set -e set -o pipefail -# Set defaults -# FIXME: Refactor this so we don't need to stay in sync with -# `z3_build.Dockerfile`. -export ASAN_BUILD="${ASAN_BUILD:-0}" -export BUILD_DOCS="${BUILD_DOCS:-0}" -export C_COMPILER="${C_COMPILER:-clang}" -export CXX_COMPILER="${CXX_COMPILER:-clang++}" -export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}" -export JAVA_BINDINGS="${JAVA_BINDINGS:-1}" -export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}" -export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}" -export PYTHON_EXECUTABLE="$(which python)" -export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" -export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}" -export TARGET_ARCH="${TARGET_ARCH:-x86_64}" -export TEST_INSTALL="${TEST_INSTALL:-1}" -export UBSAN_BUILD="${UBSAN_BUILD:-0}" -export USE_LIBGMP="${USE_LIBGMP:-0}" -export USE_LTO="${USE_LTO:-0}" -export USE_OPENMP="${USE_OPENMP:-1}" +# Get defaults +source "${SCRIPT_DIR}/ci_defaults.sh" if [ -z "${TRAVIS_BUILD_DIR}" ]; then echo "TRAVIS_BUILD_DIR must be set to root of Z3 repository" @@ -37,15 +19,11 @@ if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then exit 1 fi +# These three variables are specific to the macOS TravisCI +# implementation and are not set in `ci_defaults.sh`. export Z3_SRC_DIR="${TRAVIS_BUILD_DIR}" export Z3_BUILD_DIR="${Z3_SRC_DIR}/build" -export Z3_BUILD_TYPE="${Z3_BUILD_TYPE:-RelWithDebInfo}" -export Z3_CMAKE_GENERATOR="${Z3_CMAKE_GENERATOR:-Ninja}" -export Z3_INSTALL_PREFIX="${Z3_INSTALL_PREFIX:-/usr/local}" -export Z3_STATIC_BUILD="${Z3_STATIC_BUILD:-0}" export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test" -export Z3_WARNINGS_AS_ERRORS="${Z3_WARNINGS_AS_ERRORS:-SERIOUS_ONLY}" -export Z3_VERBOSE_BUILD_OUTPUT="${Z3_VERBOSE_BUILD_OUTPUT:-0}" # Overwrite whatever what set in TravisCI export CC="${C_COMPILER}" From eb975a49d606bcdb076b523d0506bf855ef8d267 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 5 Oct 2017 14:44:41 +0100 Subject: [PATCH 18/67] [TravisCI] Fix bug where `Z3_BUILD_TYPE` was not being passed as a Docker build argument. Also update an out of date comment. --- contrib/ci/scripts/travis_ci_linux_entry_point.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/ci/scripts/travis_ci_linux_entry_point.sh b/contrib/ci/scripts/travis_ci_linux_entry_point.sh index c0f856faa..bd2c9d2d1 100755 --- a/contrib/ci/scripts/travis_ci_linux_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_linux_entry_point.sh @@ -21,8 +21,11 @@ fi source "${SCRIPT_DIR}/ci_defaults.sh" BUILD_OPTS=() -# Override options if they have been provided. -# Otherwise the defaults in the Docker file will be used +# Pass Docker build arguments +if [ -n "${Z3_BUILD_TYPE}" ]; then + BUILD_OPTS+=("--build-arg" "Z3_BUILD_TYPE=${Z3_BUILD_TYPE}") +fi + if [ -n "${Z3_CMAKE_GENERATOR}" ]; then BUILD_OPTS+=("--build-arg" "Z3_CMAKE_GENERATOR=${Z3_CMAKE_GENERATOR}") fi From 0633d5819f8b996b3300f177efe6b1406a1285a5 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 5 Oct 2017 15:09:16 +0100 Subject: [PATCH 19/67] [TravisCI] Fix bug. `PYTHON_EXECUTABLE` should not be in common defaults. The location is dependent on the implementation. This triggered a build failure on TravisCI because the location of the default Python binary is different to what is in the Docker container. --- contrib/ci/Dockerfiles/z3_build.Dockerfile | 2 +- contrib/ci/scripts/ci_defaults.sh | 2 +- contrib/ci/scripts/travis_ci_osx_entry_point.sh | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/contrib/ci/Dockerfiles/z3_build.Dockerfile b/contrib/ci/Dockerfiles/z3_build.Dockerfile index 5f7608cf4..07504e6b9 100644 --- a/contrib/ci/Dockerfiles/z3_build.Dockerfile +++ b/contrib/ci/Dockerfiles/z3_build.Dockerfile @@ -12,7 +12,7 @@ ARG DOTNET_BINDINGS ARG JAVA_BINDINGS ARG NO_SUPPRESS_OUTPUT ARG PYTHON_BINDINGS -ARG PYTHON_EXECUTABLE +ARG PYTHON_EXECUTABLE=/usr/bin/python2.7 ARG RUN_SYSTEM_TESTS ARG RUN_UNIT_TESTS ARG TARGET_ARCH diff --git a/contrib/ci/scripts/ci_defaults.sh b/contrib/ci/scripts/ci_defaults.sh index 354ea95b7..2fb3fa52a 100644 --- a/contrib/ci/scripts/ci_defaults.sh +++ b/contrib/ci/scripts/ci_defaults.sh @@ -9,7 +9,6 @@ export DOTNET_BINDINGS="${DOTNET_BINDINGS:-1}" export JAVA_BINDINGS="${JAVA_BINDINGS:-1}" export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}" export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}" -export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}" export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}" export TARGET_ARCH="${TARGET_ARCH:-x86_64}" @@ -49,6 +48,7 @@ unset PLATFORM # NOTE: The following variables are not set here because # they are specific to the CI implementation +# PYTHON_EXECUTABLE # Z3_SRC_DIR # Z3_BUILD_DIR # Z3_SYSTEM_TEST_DIR diff --git a/contrib/ci/scripts/travis_ci_osx_entry_point.sh b/contrib/ci/scripts/travis_ci_osx_entry_point.sh index 7dd566877..ad3b0c7ab 100755 --- a/contrib/ci/scripts/travis_ci_osx_entry_point.sh +++ b/contrib/ci/scripts/travis_ci_osx_entry_point.sh @@ -19,8 +19,9 @@ if [ ! -d "${TRAVIS_BUILD_DIR}" ]; then exit 1 fi -# These three variables are specific to the macOS TravisCI +# These variables are specific to the macOS TravisCI # implementation and are not set in `ci_defaults.sh`. +export PYTHON_EXECUTABLE="${PYTHON_EXECUTABLE:-$(which python)}" export Z3_SRC_DIR="${TRAVIS_BUILD_DIR}" export Z3_BUILD_DIR="${Z3_SRC_DIR}/build" export Z3_SYSTEM_TEST_DIR="${Z3_SRC_DIR}/z3_system_test" From 6268ff1fa13d283c9b4b0461f2b4423509a554ee Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 5 Oct 2017 18:10:20 +0100 Subject: [PATCH 20/67] dom_simplify improvements with Nikolaj --- src/tactic/core/dom_simplify_tactic.cpp | 129 ++++++++++++++++-------- src/tactic/core/dom_simplify_tactic.h | 19 +++- 2 files changed, 102 insertions(+), 46 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index d4a3031cd..85b7fd9d6 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -95,13 +95,16 @@ void expr_dominators::compute_dominators() { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; SASSERT(!p.empty()); - expr * new_idom = p[0], * idom2 = 0; - for (unsigned j = 1; j < p.size(); ++j) { - if (m_doms.find(p[j], idom2)) { + expr * new_idom = 0, *idom2 = 0; + for (unsigned j = 0; j < p.size(); ++j) { + if (!new_idom) { + m_doms.find(p[j], new_idom); + } + else if (m_doms.find(p[j], idom2)) { new_idom = intersect(new_idom, idom2); } } - if (!m_doms.find(child, idom2) || idom2 != new_idom) { + if (new_idom && (!m_doms.find(child, idom2) || idom2 != new_idom)) { m_doms.insert(child, new_idom); change = true; } @@ -113,7 +116,7 @@ void expr_dominators::extract_tree() { for (auto const& kv : m_doms) { add_edge(m_tree, kv.m_value, kv.m_key); } -} +} void expr_dominators::compile(expr * e) { reset(); @@ -147,9 +150,9 @@ tactic * dom_simplify_tactic::translate(ast_manager & m) { } void dom_simplify_tactic::operator()( - goal_ref const & in, - goal_ref_buffer & result, - model_converter_ref & mc, + goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, proof_converter_ref & pc, expr_dependency_ref & core) { mc = 0; pc = 0; core = 0; @@ -162,33 +165,41 @@ void dom_simplify_tactic::operator()( } void dom_simplify_tactic::cleanup() { - m_trail.reset(); - m_args.reset(); - m_args2.reset(); - m_result.reset(); - m_dominators.reset(); + m_trail.reset(); + m_args.reset(); + m_args2.reset(); + m_result.reset(); + m_dominators.reset(); } expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr_ref r(m); - expr * c = 0, * t = 0, * e = 0; + expr * c = 0, *t = 0, *e = 0; VERIFY(m.is_ite(ite, c, t, e)); unsigned old_lvl = scope_level(); expr_ref new_c = simplify(c); if (m.is_true(new_c)) { r = simplify(t); - } - else if (m.is_false(new_c) || !assert_expr(new_c, false)) { + } else if (m.is_false(new_c) || !assert_expr(new_c, false)) { r = simplify(e); - } - else { - expr_ref new_t = simplify(t); + } else { + for (expr * child : tree(ite)) { + if (is_subexpr(child, t) && !is_subexpr(child, e)) { + simplify(child); + } + } pop(scope_level() - old_lvl); + expr_ref new_t = simplify(t); if (!assert_expr(new_c, true)) { return new_t; } - expr_ref new_e = simplify(e); + for (expr * child : tree(ite)) { + if (is_subexpr(child, e) && !is_subexpr(child, t)) { + simplify(child); + } + } pop(scope_level() - old_lvl); + expr_ref new_e = simplify(e); if (c == new_c && t == new_t && e == new_e) { r = ite; } @@ -197,7 +208,7 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { } else { TRACE("tactic", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";); - r = m.mk_ite(new_c, new_t, new_c); + r = m.mk_ite(new_c, new_t, new_e); } } return r; @@ -224,11 +235,8 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { r = simplify_or(to_app(e)); } else { - expr_dominators::tree_t const& t = m_dominators.get_tree(); - if (auto children = t.find_core(e)) { - for (expr * child : children->get_data().m_value) { - simplify(child); - } + for (expr * child : tree(e)) { + simplify(child); } if (is_app(e)) { m_args.reset(); @@ -251,27 +259,33 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { expr_ref r(m); unsigned old_lvl = scope_level(); - m_args.reset(); + + auto is_subexpr_arg = [&](expr * child, expr * except) { + if (!is_subexpr(child, except)) + return false; + for (expr * arg : *e) { + if (arg != except && is_subexpr(child, arg)) + return false; + } + return true; + }; + + expr_ref_vector args(m); for (expr * arg : *e) { - r = simplify(arg); - if (!assert_expr(r, !is_and)) { - r = is_and ? m.mk_false() : m.mk_true(); + for (expr * child : tree(arg)) { + if (is_subexpr_arg(child, arg)) { + simplify(child); + } + } + r = simplify(arg); + args.push_back(r); + if (!assert_expr(simplify(arg), !is_and)) { + r = is_and ? m.mk_false() : m.mk_true(); + return r; } - m_args.push_back(r); } pop(scope_level() - old_lvl); - m_args.reverse(); - m_args2.reset(); - for (expr * arg : m_args) { - r = simplify(arg); - if (!assert_expr(r, !is_and)) { - r = is_and ? m.mk_false() : m.mk_true(); - } - m_args2.push_back(r); - } - pop(scope_level() - old_lvl); - m_args2.reverse(); - r = is_and ? mk_and(m_args2) : mk_or(m_args2); + r = is_and ? mk_and(args) : mk_or(args); return r; } @@ -332,11 +346,36 @@ void dom_simplify_tactic::simplify_goal(goal& g) { SASSERT(scope_level() == 0); } +bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { + if (a == b) + return true; + + bool r; + if (m_subexpr_cache.find(a, b, r)) + return r; + + for (expr * e : tree(b)) { + if (is_subexpr(a, e)) { + m_subexpr_cache.insert(a, b, true); + return true; + } + } + m_subexpr_cache.insert(a, b, false); + return false; +} + +ptr_vector const & dom_simplify_tactic::tree(expr * e) { + if (auto p = m_dominators.get_tree().find_core(e)) + return p->get_data().get_value(); + return m_empty; +} + // ---------------------- // expr_substitution_simplifier bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { + m_scoped_substitution.push(); expr* tt; if (!sign) { update_substitution(t, 0); @@ -439,3 +478,7 @@ void expr_substitution_simplifier::compute_depth(expr* e) { m_expr2depth.insert(e, d + 1); } } + +tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(dom_simplify_tactic, m, alloc(expr_substitution_simplifier, m), p)); +} diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 2fa79dd1d..9fe59de23 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -23,6 +23,8 @@ Notes: #include "ast/ast.h" #include "ast/expr_substitution.h" #include "tactic/tactic.h" +#include "tactic/tactical.h" +#include "util/obj_pair_hashtable.h" class expr_dominators { @@ -89,6 +91,8 @@ private: unsigned m_scope_level; unsigned m_depth; unsigned m_max_depth; + ptr_vector m_empty; + obj_pair_map m_subexpr_cache; expr_ref simplify(expr* t); expr_ref simplify_ite(app * ite); @@ -97,9 +101,13 @@ private: expr_ref simplify_and_or(bool is_and, app * ite); void simplify_goal(goal& g); - expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(r, r)) r = t; return expr_ref(r, m); } + bool is_subexpr(expr * a, expr * b); + + expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(t, r)) r = t; return expr_ref(r, m); } void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } + ptr_vector const & tree(expr * e); + unsigned scope_level() { return m_scope_level; } void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } bool assert_expr(expr* f, bool sign) { m_scope_level++; return m_simplifier->assert_expr(f, sign); } @@ -156,8 +164,13 @@ public: SASSERT(m_subst.empty()); return alloc(expr_substitution_simplifier, m); } - - }; + +tactic * mk_dom_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()); + +/* +ADD_TACTIC("dom-simplify", "apply dominator simplification rules.", "mk_dom_simplify_tactic(m, p)") +*/ + #endif From f59cf2452d9a335785bd1691dbf04b93973193d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Oct 2017 22:20:31 +0100 Subject: [PATCH 21/67] #1284 build problems Signed-off-by: Nikolaj Bjorner --- src/tactic/core/CMakeLists.txt | 2 + src/tactic/core/dom_simplify_tactic.cpp | 1 + src/tactic/core/dom_simplify_tactic.h | 53 +++++++++++++------------ 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index f192b4fa6..16778d8dd 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -7,6 +7,7 @@ z3_add_component(core_tactics ctx_simplify_tactic.cpp der_tactic.cpp distribute_forall_tactic.cpp + dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp injectivity_tactic.cpp @@ -32,6 +33,7 @@ z3_add_component(core_tactics ctx_simplify_tactic.h der_tactic.h distribute_forall_tactic.h + dom_simplify_tactic.h elim_term_ite_tactic.h elim_uncnstr_tactic.h injectivity_tactic.h diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 85b7fd9d6..bba27cf46 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -188,6 +188,7 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { simplify(child); } } + pop(scope_level() - old_lvl); expr_ref new_t = simplify(t); if (!assert_expr(new_c, true)) { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 9fe59de23..825a173bf 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -58,32 +58,35 @@ public: }; +class dom_simplifier { + public: + dom_simplifier() {} + + virtual ~dom_simplifier() {} + /** + \brief assert_expr performs an implicit push + */ + virtual bool assert_expr(expr * t, bool sign) = 0; + + /** + \brief apply simplification. + */ + virtual void operator()(expr_ref& r) = 0; + + /** + \brief pop scopes accumulated from assertions. + */ + virtual void pop(unsigned num_scopes) = 0; + + virtual dom_simplifier * translate(ast_manager & m) = 0; + +}; + class dom_simplify_tactic : public tactic { public: - class simplifier { - public: - virtual ~simplifier() {} - /** - \brief assert_expr performs an implicit push - */ - virtual bool assert_expr(expr * t, bool sign) = 0; - - /** - \brief apply simplification. - */ - virtual void operator()(expr_ref& r) = 0; - - /** - \brief pop scopes accumulated from assertions. - */ - virtual void pop(unsigned num_scopes) = 0; - - virtual simplifier * translate(ast_manager & m); - - }; private: ast_manager& m; - simplifier* m_simplifier; + dom_simplifier* m_simplifier; params_ref m_params; expr_ref_vector m_trail, m_args, m_args2; obj_map m_result; @@ -115,7 +118,7 @@ private: void init(goal& g); public: - dom_simplify_tactic(ast_manager & m, simplifier* s, params_ref const & p = params_ref()): + 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_args2(m), m_dominators(m), @@ -138,7 +141,7 @@ public: virtual void cleanup(); }; -class expr_substitution_simplifier : public dom_simplify_tactic::simplifier { +class expr_substitution_simplifier : public dom_simplifier { ast_manager& m; expr_substitution m_subst; scoped_expr_substitution m_scoped_substitution; @@ -160,7 +163,7 @@ public: virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); } - virtual simplifier * translate(ast_manager & m) { + virtual dom_simplifier * translate(ast_manager & m) { SASSERT(m_subst.empty()); return alloc(expr_substitution_simplifier, m); } From eac659f748fc3209fca947556d94d9b08a3c8c82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 11:34:14 +0100 Subject: [PATCH 22/67] deal with empty set of post-orders Signed-off-by: Nikolaj Bjorner --- src/muz/rel/karr_relation.cpp | 4 ++-- .../transforms/dl_mk_interp_tail_simplifier.cpp | 4 ++-- src/smt/theory_lra.cpp | 4 ++-- src/tactic/core/dom_simplify_tactic.cpp | 14 ++++++++------ src/tactic/core/dom_simplify_tactic.h | 4 ++-- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index 572d5e8d5..c8a489d69 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -111,8 +111,8 @@ namespace datalog { void filter_interpreted(app* cond) { rational one(1), mone(-1); - expr* e1, *e2, *en; - var* v, *w; + expr* e1 = 0, *e2 = 0, *en = 0; + var* v = 0, *w = 0; rational n1, n2; expr_ref_vector conjs(m); flatten_and(cond, conjs); diff --git a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp index 30505a5e8..7bd35b4ef 100644 --- a/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp @@ -398,8 +398,8 @@ namespace datalog { } bool mk_interp_tail_simplifier::propagate_variable_equivalences(rule * r, rule_ref& res) { - if (!m_context.get_params ().xform_tail_simplifier_pve ()) - return false; + if (!m_context.get_params ().xform_tail_simplifier_pve ()) + return false; unsigned u_len = r->get_uninterpreted_tail_size(); unsigned len = r->get_tail_size(); if (u_len == len) { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0bb76cd90..7fec6f836 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -721,7 +721,7 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1, *n2; + expr* n1 = 0, *n2 = 0; rational r; lra_lp::bound_kind k; theory_var v = null_theory_var; @@ -862,7 +862,7 @@ namespace smt { void relevant_eh(app* n) { TRACE("arith", tout << mk_pp(n, m) << "\n";); - expr* n1, *n2; + expr* n1 = 0, *n2 = 0; if (a.is_mod(n, n1, n2)) mk_idiv_mod_axioms(n1, n2); else if (a.is_rem(n, n1, n2)) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index bba27cf46..17262a9d6 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -90,8 +90,8 @@ void expr_dominators::compute_dominators() { bool change = true; while (change) { change = false; - SASSERT(m_post2expr.back() == e); - for (unsigned i = 0; i < m_post2expr.size() - 1; ++i) { + SASSERT(m_post2expr.empty() || m_post2expr.back() == e); + for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; SASSERT(!p.empty()); @@ -167,7 +167,6 @@ void dom_simplify_tactic::operator()( void dom_simplify_tactic::cleanup() { m_trail.reset(); m_args.reset(); - m_args2.reset(); m_result.reset(); m_dominators.reset(); } @@ -180,9 +179,11 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr_ref new_c = simplify(c); if (m.is_true(new_c)) { r = simplify(t); - } else if (m.is_false(new_c) || !assert_expr(new_c, false)) { + } + else if (m.is_false(new_c) || !assert_expr(new_c, false)) { r = simplify(e); - } else { + } + else { for (expr * child : tree(ite)) { if (is_subexpr(child, t) && !is_subexpr(child, e)) { simplify(child); @@ -254,6 +255,7 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { cache(e0, r); TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); --m_depth; + m_subexpr_cache.reset(); return r; } @@ -361,7 +363,7 @@ bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { return true; } } - m_subexpr_cache.insert(a, b, false); + m_subexpr_cache.insert(a, b, false); return false; } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 825a173bf..c62651c5c 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -88,7 +88,7 @@ private: ast_manager& m; dom_simplifier* m_simplifier; params_ref m_params; - expr_ref_vector m_trail, m_args, m_args2; + expr_ref_vector m_trail, m_args; obj_map m_result; expr_dominators m_dominators; unsigned m_scope_level; @@ -120,7 +120,7 @@ private: 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_args2(m), + m_trail(m), m_args(m), m_dominators(m), m_scope_level(0), m_depth(0), m_max_depth(1024) {} From 6df628edc7043a08dd11eae3d2ab8d44e07a172c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 11:45:29 +0100 Subject: [PATCH 23/67] pin elements in expr2depth Signed-off-by: Nikolaj Bjorner --- src/smt/smt_implied_equalities.cpp | 2 +- src/smt/theory_lra.cpp | 2 +- src/tactic/bv/bv_bounds_tactic.cpp | 6 ++++-- src/tactic/core/dom_simplify_tactic.cpp | 2 ++ src/tactic/core/dom_simplify_tactic.h | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/smt/smt_implied_equalities.cpp b/src/smt/smt_implied_equalities.cpp index 7d54e714e..d021708fc 100644 --- a/src/smt/smt_implied_equalities.cpp +++ b/src/smt/smt_implied_equalities.cpp @@ -284,7 +284,7 @@ namespace smt { } lbool reduce_cond(model_ref& model, expr* e) { - expr* e1, *e2; + expr* e1 = 0, *e2 = 0; if (m.is_eq(e, e1, e2) && m_array_util.is_as_array(e1) && m_array_util.is_as_array(e2)) { if (e1 == e2) { return l_true; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 7fec6f836..292d2ab0d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -689,7 +689,7 @@ namespace smt { SASSERT(!ctx().b_internalized(atom)); bool_var bv = ctx().mk_bool_var(atom); ctx().set_var_theory(bv, get_id()); - expr* n1, *n2; + expr* n1 = 0, *n2 = 0; rational r; lra_lp::bound_kind k; theory_var v = null_theory_var; diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index d2cd0d66c..1f0bb8473 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -70,11 +70,13 @@ struct interval { if (is_wrapped()) { // l >= b.l >= b.h >= h return b.is_wrapped() && h <= b.h && l >= b.l; - } else if (b.is_wrapped()) { + } + else if (b.is_wrapped()) { // b.l > b.h >= h >= l // h >= l >= b.l > b.h return h <= b.h || l >= b.l; - } else { + } + else { // return l >= b.l && h <= b.h; } diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 17262a9d6..08037fe18 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -430,6 +430,8 @@ void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) { if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { compute_depth(lhs); compute_depth(rhs); + m_trail.push_back(lhs); + m_trail.push_back(rhs); if (is_gt(lhs, rhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); m_scoped_substitution.insert(lhs, rhs, pr); diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index c62651c5c..25fb7c24f 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -146,6 +146,7 @@ class expr_substitution_simplifier : public dom_simplifier { expr_substitution m_subst; scoped_expr_substitution m_scoped_substitution; obj_map m_expr2depth; + expr_ref_vector m_trail; // move from asserted_formulas to here.. void compute_depth(expr* e); @@ -153,7 +154,7 @@ class expr_substitution_simplifier : public dom_simplifier { unsigned depth(expr* e) { return m_expr2depth[e]; } public: - expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst) {} + expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {} virtual ~expr_substitution_simplifier() {} virtual bool assert_expr(expr * t, bool sign); From cb548404bc1ad5a55628e1dd23fc4efe69de8856 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 12:08:37 +0100 Subject: [PATCH 24/67] bail out dominators after log number of steps Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/bv_bounds_tactic.cpp | 1227 ++++++++++++++--------- src/tactic/core/dom_simplify_tactic.cpp | 25 +- src/tactic/core/dom_simplify_tactic.h | 8 +- 3 files changed, 792 insertions(+), 468 deletions(-) diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 1f0bb8473..2d5eb216a 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -18,6 +18,7 @@ Author: #include "tactic/bv/bv_bounds_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" +#include "tactic/core/dom_simplify_tactic.h" #include "ast/bv_decl_plugin.h" #include "ast/ast_pp.h" #include @@ -29,509 +30,825 @@ static uint64 uMaxInt(unsigned sz) { namespace { -struct interval { - // l < h: [l, h] - // l > h: [0, h] U [l, UMAX_INT] - uint64 l, h; - unsigned sz; - bool tight; + struct interval { + // l < h: [l, h] + // l > h: [0, h] U [l, UMAX_INT] + uint64 l, h; + unsigned sz; + bool tight; - interval() {} - interval(uint64 l, uint64 h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { - // canonicalize full set - if (is_wrapped() && l == h + 1) { - this->l = 0; - this->h = uMaxInt(sz); - } - SASSERT(invariant()); - } - - bool invariant() const { - return l <= uMaxInt(sz) && h <= uMaxInt(sz) && - (!is_wrapped() || l != h+1); - } - - bool is_full() const { return l == 0 && h == uMaxInt(sz); } - bool is_wrapped() const { return l > h; } - bool is_singleton() const { return l == h; } - - bool operator==(const interval& b) const { - SASSERT(sz == b.sz); - return l == b.l && h == b.h && tight == b.tight; - } - bool operator!=(const interval& b) const { return !(*this == b); } - - bool implies(const interval& b) const { - if (b.is_full()) - return true; - if (is_full()) - return false; - - if (is_wrapped()) { - // l >= b.l >= b.h >= h - return b.is_wrapped() && h <= b.h && l >= b.l; - } - else if (b.is_wrapped()) { - // b.l > b.h >= h >= l - // h >= l >= b.l > b.h - return h <= b.h || l >= b.l; - } - else { - // - return l >= b.l && h <= b.h; - } - } - - /// return false if intersection is unsat - bool intersect(const interval& b, interval& result) const { - if (is_full() || *this == b) { - result = b; - return true; - } - if (b.is_full()) { - result = *this; - return true; + interval() {} + interval(uint64 l, uint64 h, unsigned sz, bool tight = false) : l(l), h(h), sz(sz), tight(tight) { + // canonicalize full set + if (is_wrapped() && l == h + 1) { + this->l = 0; + this->h = uMaxInt(sz); + } + SASSERT(invariant()); } - if (is_wrapped()) { - if (b.is_wrapped()) { - if (h >= b.l) { - result = b; - } else if (b.h >= l) { - result = *this; + bool invariant() const { + return l <= uMaxInt(sz) && h <= uMaxInt(sz) && + (!is_wrapped() || l != h+1); + } + + bool is_full() const { return l == 0 && h == uMaxInt(sz); } + bool is_wrapped() const { return l > h; } + bool is_singleton() const { return l == h; } + + bool operator==(const interval& b) const { + SASSERT(sz == b.sz); + return l == b.l && h == b.h && tight == b.tight; + } + bool operator!=(const interval& b) const { return !(*this == b); } + + bool implies(const interval& b) const { + if (b.is_full()) + return true; + if (is_full()) + return false; + + if (is_wrapped()) { + // l >= b.l >= b.h >= h + return b.is_wrapped() && h <= b.h && l >= b.l; + } + else if (b.is_wrapped()) { + // b.l > b.h >= h >= l + // h >= l >= b.l > b.h + return h <= b.h || l >= b.l; + } + else { + // + return l >= b.l && h <= b.h; + } + } + + /// return false if intersection is unsat + bool intersect(const interval& b, interval& result) const { + if (is_full() || *this == b) { + result = b; + return true; + } + if (b.is_full()) { + result = *this; + return true; + } + + if (is_wrapped()) { + if (b.is_wrapped()) { + if (h >= b.l) { + result = b; + } else if (b.h >= l) { + result = *this; + } else { + result = interval(std::max(l, b.l), std::min(h, b.h), sz); + } } else { - result = interval(std::max(l, b.l), std::min(h, b.h), sz); + return b.intersect(*this, result); + } + } + else if (b.is_wrapped()) { + // ... b.h ... l ... h ... b.l .. + if (h < b.l && l > b.h) { + return false; + } + // ... l ... b.l ... h ... + if (h >= b.l && l <= b.h) { + result = b; + } else if (h >= b.l) { + result = interval(b.l, h, sz); + } else { + // ... l .. b.h .. h .. b.l ... + SASSERT(l <= b.h); + result = interval(l, std::min(h, b.h), sz); } } else { - return b.intersect(*this, result); - } - } else if (b.is_wrapped()) { - // ... b.h ... l ... h ... b.l .. - if (h < b.l && l > b.h) { - return false; - } - // ... l ... b.l ... h ... - if (h >= b.l && l <= b.h) { - result = b; - } else if (h >= b.l) { - result = interval(b.l, h, sz); - } else { - // ... l .. b.h .. h .. b.l ... - SASSERT(l <= b.h); - result = interval(l, std::min(h, b.h), sz); - } - } else { - if (l > b.h || h < b.l) - return false; + if (l > b.h || h < b.l) + return false; - // 0 .. l.. l' ... h ... h' - result = interval(std::max(l, b.l), std::min(h, b.h), sz, tight && b.tight); - } - return true; - } - - /// return false if negation is empty - bool negate(interval& result) const { - if (!tight) { - result = interval(0, uMaxInt(sz), true); + // 0 .. l.. l' ... h ... h' + result = interval(std::max(l, b.l), std::min(h, b.h), sz, tight && b.tight); + } return true; } - if (is_full()) - return false; - if (l == 0) { - result = interval(h + 1, uMaxInt(sz), sz); - } else if (uMaxInt(sz) == h) { - result = interval(0, l - 1, sz); - } else { - result = interval(h + 1, l - 1, sz); + /// return false if negation is empty + bool negate(interval& result) const { + if (!tight) { + result = interval(0, uMaxInt(sz), true); + return true; + } + + if (is_full()) + return false; + if (l == 0) { + result = interval(h + 1, uMaxInt(sz), sz); + } else if (uMaxInt(sz) == h) { + result = interval(0, l - 1, sz); + } else { + result = interval(h + 1, l - 1, sz); + } + return true; } - return true; - } -}; + }; #ifdef _TRACE -std::ostream& operator<<(std::ostream& o, const interval& I) { - o << "[" << I.l << ", " << I.h << "]"; - return o; -} -#endif - - -struct undo_bound { - expr* e; - interval b; - bool fresh; - undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} -}; - -class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier { - typedef obj_map map; - typedef obj_map expr_set; - typedef obj_map expr_cnt; - - ast_manager& m; - params_ref m_params; - bool m_propagate_eq; - bv_util m_bv; - vector m_scopes; - map m_bound; - svector m_expr_vars; - svector m_bound_exprs; - - bool is_number(expr *e, uint64& n, unsigned& sz) const { - rational r; - if (m_bv.is_numeral(e, r, sz) && sz <= 64) { - n = r.get_uint64(); - return true; - } - return false; - } - - bool is_bound(expr *e, expr*& v, interval& b) const { - uint64 n; - expr *lhs, *rhs; - unsigned sz; - - if (m_bv.is_bv_ule(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { // C ule x <=> x uge C - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, uMaxInt(sz), sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { // x ule C - b = interval(0, n, sz, true); - v = lhs; - return true; - } - } else if (m_bv.is_bv_sle(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { // C sle x <=> x sge C - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, (1ull << (sz-1)) - 1, sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { // x sle C - b = interval(1ull << (sz-1), n, sz, true); - v = lhs; - return true; - } - } else if (m.is_eq(e, lhs, rhs)) { - if (is_number(lhs, n, sz)) { - if (m_bv.is_numeral(rhs)) - return false; - b = interval(n, n, sz, true); - v = rhs; - return true; - } - if (is_number(rhs, n, sz)) { - b = interval(n, n, sz, true); - v = lhs; - return true; - } - } - return false; - } - -#if 0 - expr_set* get_expr_vars(expr* t) { - unsigned id = t->get_id(); - m_expr_vars.reserve(id + 1); - expr_set*& entry = m_expr_vars[id]; - if (entry) - return entry; - - expr_set* set = alloc(expr_set); - entry = set; - - if (!m_bv.is_numeral(t)) - set->insert(t, true); - - if (!is_app(t)) - return set; - - app* a = to_app(t); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_set* set_arg = get_expr_vars(a->get_arg(i)); - for (expr_set::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { - set->insert(I->m_key, true); - } - } - return set; + std::ostream& operator<<(std::ostream& o, const interval& I) { + o << "[" << I.l << ", " << I.h << "]"; + return o; } #endif -#if 0 - expr_cnt* get_expr_bounds(expr* t) { - unsigned id = t->get_id(); - m_bound_exprs.reserve(id + 1); - expr_cnt*& entry = m_bound_exprs[id]; - if (entry) - return entry; - expr_cnt* set = alloc(expr_cnt); - entry = set; - - if (!is_app(t)) - return set; - - interval b; + struct undo_bound { expr* e; - if (is_bound(t, e, b)) { - set->insert_if_not_there2(e, 0)->get_data().m_value++; + interval b; + bool fresh; + undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {} + }; + + class bv_bounds_simplifier : public ctx_simplify_tactic::simplifier { + typedef obj_map map; + typedef obj_map expr_set; + typedef obj_map expr_cnt; + + ast_manager& m; + params_ref m_params; + bool m_propagate_eq; + bv_util m_bv; + vector m_scopes; + map m_bound; + svector m_expr_vars; + svector m_bound_exprs; + + bool is_number(expr *e, uint64& n, unsigned& sz) const { + rational r; + if (m_bv.is_numeral(e, r, sz) && sz <= 64) { + n = r.get_uint64(); + return true; + } + return false; } - app* a = to_app(t); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_cnt* set_arg = get_expr_bounds(a->get_arg(i)); - for (expr_cnt::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { - set->insert_if_not_there2(I->m_key, 0)->get_data().m_value += I->m_value; + bool is_bound(expr *e, expr*& v, interval& b) const { + uint64 n; + expr *lhs = 0, *rhs = 0; + unsigned sz; + + if (m_bv.is_bv_ule(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C ule x <=> x uge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, uMaxInt(sz), sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x ule C + b = interval(0, n, sz, true); + v = lhs; + return true; + } + } + else if (m_bv.is_bv_sle(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C sle x <=> x sge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, (1ull << (sz-1)) - 1, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x sle C + b = interval(1ull << (sz-1), n, sz, true); + v = lhs; + return true; + } + } else if (m.is_eq(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, n, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { + b = interval(n, n, sz, true); + v = lhs; + return true; + } } + return false; + } + +#if 0 + expr_set* get_expr_vars(expr* t) { + unsigned id = t->get_id(); + m_expr_vars.reserve(id + 1); + expr_set*& entry = m_expr_vars[id]; + if (entry) + return entry; + + expr_set* set = alloc(expr_set); + entry = set; + + if (!m_bv.is_numeral(t)) + set->insert(t, true); + + if (!is_app(t)) + return set; + + app* a = to_app(t); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr_set* set_arg = get_expr_vars(a->get_arg(i)); + for (expr_set::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { + set->insert(I->m_key, true); + } + } + return set; } - return set; - } #endif -public: - bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { - updt_params(p); - } +#if 0 + expr_cnt* get_expr_bounds(expr* t) { + unsigned id = t->get_id(); + m_bound_exprs.reserve(id + 1); + expr_cnt*& entry = m_bound_exprs[id]; + if (entry) + return entry; - virtual void updt_params(params_ref const & p) { - m_propagate_eq = p.get_bool("propagate_eq", false); - } + expr_cnt* set = alloc(expr_cnt); + entry = set; - static void get_param_descrs(param_descrs& r) { - r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); - } + if (!is_app(t)) + return set; - virtual ~bv_bounds_simplifier() { - for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { - dealloc(m_expr_vars[i]); - } - for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { - dealloc(m_bound_exprs[i]); - } - } - - virtual bool assert_expr(expr * t, bool sign) { - while (m.is_not(t, t)) { - sign = !sign; - } - - interval b; - expr* t1; - if (is_bound(t, t1, b)) { - SASSERT(!m_bv.is_numeral(t1)); - if (sign) - VERIFY(b.negate(b)); - - TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); - map::obj_map_entry* e = m_bound.find_core(t1); - if (e) { - interval& old = e->get_data().m_value; - interval intr; - if (!old.intersect(b, intr)) - return false; - if (old == intr) - return true; - m_scopes.insert(undo_bound(t1, old, false)); - old = intr; - } else { - m_bound.insert(t1, b); - m_scopes.insert(undo_bound(t1, interval(), true)); - } - } - return true; - } - - virtual bool simplify(expr* t, expr_ref& result) { - expr* t1; - interval b; - - if (m_bound.find(t, b) && b.is_singleton()) { - result = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); - return true; - } - - if (!m.is_bool(t)) - return false; - - bool sign = false; - while (m.is_not(t, t)) { - sign = !sign; - } - - if (!is_bound(t, t1, b)) - return false; - - if (sign && b.tight) { - sign = false; - if (!b.negate(b)) { - result = m.mk_false(); - return true; - } - } - - interval ctx, intr; - result = 0; - - if (b.is_full() && b.tight) { - result = m.mk_true(); - } else if (m_bound.find(t1, ctx)) { - if (ctx.implies(b)) { - result = m.mk_true(); - } else if (!b.intersect(ctx, intr)) { - result = m.mk_false(); - } else if (m_propagate_eq && intr.is_singleton()) { - result = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), - m.get_sort(t1))); - } - } - - CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";); - if (sign && result != 0) - result = m.mk_not(result); - return result != 0; - } - - // check if t contains v - ptr_vector todo; - bool contains(expr* t, expr* v) { - ast_fast_mark1 mark; - todo.push_back(t); - while (!todo.empty()) { - t = todo.back(); - todo.pop_back(); - if (mark.is_marked(t)) { - continue; - } - if (t == v) { - todo.reset(); - return true; - } - mark.mark(t); - - if (!is_app(t)) { - continue; - } - app* a = to_app(t); - todo.append(a->get_num_args(), a->get_args()); - } - return false; - } - - bool contains_bound(expr* t) { - ast_fast_mark1 mark1; - ast_fast_mark2 mark2; - - todo.push_back(t); - while (!todo.empty()) { - t = todo.back(); - todo.pop_back(); - if (mark1.is_marked(t)) { - continue; - } - mark1.mark(t); - - if (!is_app(t)) { - continue; - } interval b; expr* e; if (is_bound(t, e, b)) { - if (mark2.is_marked(e)) { - todo.reset(); - return true; - } - mark2.mark(e); - if (m_bound.contains(e)) { - todo.reset(); - return true; - } + set->insert_if_not_there2(e, 0)->get_data().m_value++; } app* a = to_app(t); - todo.append(a->get_num_args(), a->get_args()); - } - return false; - } - - virtual bool may_simplify(expr* t) { - if (m_bv.is_numeral(t)) - return false; - - while (m.is_not(t, t)); - - for (auto & v : m_bound) { - if (contains(t, v.m_key)) return true; - } - -#if 0 - expr_set* used_exprs = get_expr_vars(t); - for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { - if (contains(t, I->m_key)) return true; - if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) - return true; + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr_cnt* set_arg = get_expr_bounds(a->get_arg(i)); + for (expr_cnt::iterator I = set_arg->begin(), E = set_arg->end(); I != E; ++I) { + set->insert_if_not_there2(I->m_key, 0)->get_data().m_value += I->m_value; + } + } + return set; } #endif - expr* t1; - interval b; - // skip common case: single bound constraint without any context for simplification - if (is_bound(t, t1, b)) { - return b.is_full() || m_bound.contains(t1); + public: + bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { + updt_params(p); } - if (contains_bound(t)) { - return true; + virtual void updt_params(params_ref const & p) { + m_propagate_eq = p.get_bool("propagate_eq", false); } -#if 0 - expr_cnt* bounds = get_expr_bounds(t); - for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { - if (I->m_value > 1 || m_bound.contains(I->m_key)) - return true; - } -#endif - return false; - } - virtual void pop(unsigned num_scopes) { - TRACE("bv", tout << "pop: " << num_scopes << "\n";); - if (m_scopes.empty()) - return; - unsigned target = m_scopes.size() - num_scopes; - if (target == 0) { - m_bound.reset(); - m_scopes.reset(); - return; + static void get_param_descrs(param_descrs& r) { + r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); } - for (unsigned i = m_scopes.size()-1; i >= target; --i) { - undo_bound& undo = m_scopes[i]; - SASSERT(m_bound.contains(undo.e)); - if (undo.fresh) { - m_bound.erase(undo.e); - } else { - m_bound.insert(undo.e, undo.b); + + virtual ~bv_bounds_simplifier() { + for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { + dealloc(m_expr_vars[i]); + } + for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { + dealloc(m_bound_exprs[i]); } } - m_scopes.shrink(target); - } - virtual simplifier * translate(ast_manager & m) { - return alloc(bv_bounds_simplifier, m, m_params); - } + virtual bool assert_expr(expr * t, bool sign) { + while (m.is_not(t, t)) { + sign = !sign; + } - virtual unsigned scope_level() const { - return m_scopes.size(); - } -}; + interval b; + expr* t1; + if (is_bound(t, t1, b)) { + SASSERT(!m_bv.is_numeral(t1)); + if (sign) + VERIFY(b.negate(b)); + + TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); + map::obj_map_entry* e = m_bound.find_core(t1); + if (e) { + interval& old = e->get_data().m_value; + interval intr; + if (!old.intersect(b, intr)) + return false; + if (old == intr) + return true; + m_scopes.insert(undo_bound(t1, old, false)); + old = intr; + } else { + m_bound.insert(t1, b); + m_scopes.insert(undo_bound(t1, interval(), true)); + } + } + return true; + } + + virtual bool simplify(expr* t, expr_ref& result) { + expr* t1; + interval b; + + if (m_bound.find(t, b) && b.is_singleton()) { + result = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); + return true; + } + + if (!m.is_bool(t)) + return false; + + bool sign = false; + while (m.is_not(t, t)) { + sign = !sign; + } + + if (!is_bound(t, t1, b)) + return false; + + if (sign && b.tight) { + sign = false; + if (!b.negate(b)) { + result = m.mk_false(); + return true; + } + } + + interval ctx, intr; + result = 0; + + if (b.is_full() && b.tight) { + result = m.mk_true(); + } else if (m_bound.find(t1, ctx)) { + if (ctx.implies(b)) { + result = m.mk_true(); + } else if (!b.intersect(ctx, intr)) { + result = m.mk_false(); + } else if (m_propagate_eq && intr.is_singleton()) { + result = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), + m.get_sort(t1))); + } + } + + CTRACE("bv", result != 0, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";); + if (sign && result != 0) + result = m.mk_not(result); + return result != 0; + } + + // check if t contains v + ptr_vector todo; + bool contains(expr* t, expr* v) { + ast_fast_mark1 mark; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark.is_marked(t)) { + continue; + } + if (t == v) { + todo.reset(); + return true; + } + mark.mark(t); + + if (!is_app(t)) { + continue; + } + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + bool contains_bound(expr* t) { + ast_fast_mark1 mark1; + ast_fast_mark2 mark2; + + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark1.is_marked(t)) { + continue; + } + mark1.mark(t); + + if (!is_app(t)) { + continue; + } + interval b; + expr* e; + if (is_bound(t, e, b)) { + if (mark2.is_marked(e)) { + todo.reset(); + return true; + } + mark2.mark(e); + if (m_bound.contains(e)) { + todo.reset(); + return true; + } + } + + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + virtual bool may_simplify(expr* t) { + if (m_bv.is_numeral(t)) + return false; + + while (m.is_not(t, t)); + + for (auto & v : m_bound) { + if (contains(t, v.m_key)) return true; + } + +#if 0 + expr_set* used_exprs = get_expr_vars(t); + for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { + if (contains(t, I->m_key)) return true; + if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) + return true; + } +#endif + + expr* t1; + interval b; + // skip common case: single bound constraint without any context for simplification + if (is_bound(t, t1, b)) { + return b.is_full() || m_bound.contains(t1); + } + + if (contains_bound(t)) { + return true; + } +#if 0 + expr_cnt* bounds = get_expr_bounds(t); + for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { + if (I->m_value > 1 || m_bound.contains(I->m_key)) + return true; + } +#endif + return false; + } + + virtual void pop(unsigned num_scopes) { + TRACE("bv", tout << "pop: " << num_scopes << "\n";); + if (m_scopes.empty()) + return; + unsigned target = m_scopes.size() - num_scopes; + if (target == 0) { + m_bound.reset(); + m_scopes.reset(); + return; + } + for (unsigned i = m_scopes.size()-1; i >= target; --i) { + undo_bound& undo = m_scopes[i]; + SASSERT(m_bound.contains(undo.e)); + if (undo.fresh) { + m_bound.erase(undo.e); + } else { + m_bound.insert(undo.e, undo.b); + } + } + m_scopes.shrink(target); + } + + virtual simplifier * translate(ast_manager & m) { + return alloc(bv_bounds_simplifier, m, m_params); + } + + virtual unsigned scope_level() const { + return m_scopes.size(); + } + }; + + + class dom_bv_bounds_simplifier : public dom_simplifier { + typedef obj_map map; + typedef obj_map expr_set; + typedef obj_map expr_cnt; + + ast_manager& m; + params_ref m_params; + bool m_propagate_eq; + bv_util m_bv; + vector m_scopes; + map m_bound; + svector m_expr_vars; + svector m_bound_exprs; + + bool is_number(expr *e, uint64& n, unsigned& sz) const { + rational r; + if (m_bv.is_numeral(e, r, sz) && sz <= 64) { + n = r.get_uint64(); + return true; + } + return false; + } + + bool is_bound(expr *e, expr*& v, interval& b) const { + uint64 n; + expr *lhs = 0, *rhs = 0; + unsigned sz; + + if (m_bv.is_bv_ule(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C ule x <=> x uge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, uMaxInt(sz), sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x ule C + b = interval(0, n, sz, true); + v = lhs; + return true; + } + } + else if (m_bv.is_bv_sle(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { // C sle x <=> x sge C + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, (1ull << (sz-1)) - 1, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { // x sle C + b = interval(1ull << (sz-1), n, sz, true); + v = lhs; + return true; + } + } else if (m.is_eq(e, lhs, rhs)) { + if (is_number(lhs, n, sz)) { + if (m_bv.is_numeral(rhs)) + return false; + b = interval(n, n, sz, true); + v = rhs; + return true; + } + if (is_number(rhs, n, sz)) { + b = interval(n, n, sz, true); + v = lhs; + return true; + } + } + return false; + } + + + public: + dom_bv_bounds_simplifier(ast_manager& m, params_ref const& p) : m(m), m_params(p), m_bv(m) { + updt_params(p); + } + + virtual void updt_params(params_ref const & p) { + m_propagate_eq = p.get_bool("propagate_eq", false); + } + + static void get_param_descrs(param_descrs& r) { + r.insert("propagate-eq", CPK_BOOL, "(default: false) propagate equalities from inequalities"); + } + + virtual ~dom_bv_bounds_simplifier() { + for (unsigned i = 0, e = m_expr_vars.size(); i < e; ++i) { + dealloc(m_expr_vars[i]); + } + for (unsigned i = 0, e = m_bound_exprs.size(); i < e; ++i) { + dealloc(m_bound_exprs[i]); + } + } + + virtual bool assert_expr(expr * t, bool sign) { + while (m.is_not(t, t)) { + sign = !sign; + } + + interval b; + expr* t1; + if (is_bound(t, t1, b)) { + SASSERT(!m_bv.is_numeral(t1)); + if (sign) + VERIFY(b.negate(b)); + + TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";); + map::obj_map_entry* e = m_bound.find_core(t1); + if (e) { + interval& old = e->get_data().m_value; + interval intr; + if (!old.intersect(b, intr)) + return false; + if (old == intr) + return true; + m_scopes.insert(undo_bound(t1, old, false)); + old = intr; + } else { + m_bound.insert(t1, b); + m_scopes.insert(undo_bound(t1, interval(), true)); + } + } + return true; + } + + virtual void operator()(expr_ref& r) { + expr* t1, * t = r; + interval b; + + if (m_bound.find(t, b) && b.is_singleton()) { + r = m_bv.mk_numeral(b.l, m_bv.get_bv_size(t)); + return; + } + + if (!m.is_bool(t)) + return; + + bool sign = false; + while (m.is_not(t, t)) { + sign = !sign; + } + + if (!is_bound(t, t1, b)) + return; + + if (sign && b.tight) { + sign = false; + if (!b.negate(b)) { + r = m.mk_false(); + return; + } + } + + interval ctx, intr; + bool unchanged = false; + if (b.is_full() && b.tight) { + r = m.mk_true(); + } else if (m_bound.find(t1, ctx)) { + if (ctx.implies(b)) { + r = m.mk_true(); + } else if (!b.intersect(ctx, intr)) { + r = m.mk_false(); + } else if (m_propagate_eq && intr.is_singleton()) { + r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), + m.get_sort(t1))); + } + } + else { + unchanged = true; + } + + CTRACE("bv", !unchanged, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); + if (sign && unchanged) + r = m.mk_not(r); + } + + // check if t contains v + ptr_vector todo; + bool contains(expr* t, expr* v) { + ast_fast_mark1 mark; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark.is_marked(t)) { + continue; + } + if (t == v) { + todo.reset(); + return true; + } + mark.mark(t); + + if (!is_app(t)) { + continue; + } + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + bool contains_bound(expr* t) { + ast_fast_mark1 mark1; + ast_fast_mark2 mark2; + + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark1.is_marked(t)) { + continue; + } + mark1.mark(t); + + if (!is_app(t)) { + continue; + } + interval b; + expr* e; + if (is_bound(t, e, b)) { + if (mark2.is_marked(e)) { + todo.reset(); + return true; + } + mark2.mark(e); + if (m_bound.contains(e)) { + todo.reset(); + return true; + } + } + + app* a = to_app(t); + todo.append(a->get_num_args(), a->get_args()); + } + return false; + } + + virtual bool may_simplify(expr* t) { + if (m_bv.is_numeral(t)) + return false; + + while (m.is_not(t, t)); + + for (auto & v : m_bound) { + if (contains(t, v.m_key)) return true; + } + +#if 0 + expr_set* used_exprs = get_expr_vars(t); + for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { + if (contains(t, I->m_key)) return true; + if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) + return true; + } +#endif + + expr* t1; + interval b; + // skip common case: single bound constraint without any context for simplification + if (is_bound(t, t1, b)) { + return b.is_full() || m_bound.contains(t1); + } + + if (contains_bound(t)) { + return true; + } +#if 0 + expr_cnt* bounds = get_expr_bounds(t); + for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { + if (I->m_value > 1 || m_bound.contains(I->m_key)) + return true; + } +#endif + return false; + } + + virtual void pop(unsigned num_scopes) { + TRACE("bv", tout << "pop: " << num_scopes << "\n";); + if (m_scopes.empty()) + return; + unsigned target = m_scopes.size() - num_scopes; + if (target == 0) { + m_bound.reset(); + m_scopes.reset(); + return; + } + for (unsigned i = m_scopes.size()-1; i >= target; --i) { + undo_bound& undo = m_scopes[i]; + SASSERT(m_bound.contains(undo.e)); + if (undo.fresh) { + m_bound.erase(undo.e); + } else { + m_bound.insert(undo.e, undo.b); + } + } + m_scopes.shrink(target); + } + + virtual dom_simplifier * translate(ast_manager & m) { + return alloc(dom_bv_bounds_simplifier, m, m_params); + } + + virtual unsigned scope_level() const { + return m_scopes.size(); + } + }; } tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p) { return clean(alloc(ctx_simplify_tactic, m, alloc(bv_bounds_simplifier, m, p), p)); } + +tactic * mk_dom_bv_bounds_tactic(ast_manager & m, params_ref const & p) { + return clean(alloc(dom_simplify_tactic, m, alloc(dom_bv_bounds_simplifier, m, p), p)); +} diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 08037fe18..d38324db9 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -83,11 +83,12 @@ expr* expr_dominators::intersect(expr* x, expr * y) { return x; } -void expr_dominators::compute_dominators() { +bool expr_dominators::compute_dominators() { expr * e = m_root; SASSERT(m_doms.empty()); m_doms.insert(e, e); bool change = true; + unsigned iterations = 1; while (change) { change = false; SASSERT(m_post2expr.empty() || m_post2expr.back() == e); @@ -109,7 +110,12 @@ void expr_dominators::compute_dominators() { change = true; } } + iterations *= 2; + if (change && iterations > m_post2expr.size()) { + return false; + } } + return true; } void expr_dominators::extract_tree() { @@ -118,17 +124,18 @@ void expr_dominators::extract_tree() { } } -void expr_dominators::compile(expr * e) { +bool expr_dominators::compile(expr * e) { reset(); m_root = e; compute_post_order(); - compute_dominators(); + if (!compute_dominators()) return false; extract_tree(); + return true; } -void expr_dominators::compile(unsigned sz, expr * const* es) { +bool expr_dominators::compile(unsigned sz, expr * const* es) { expr_ref e(m.mk_and(sz, es), m); - compile(e); + return compile(e); } void expr_dominators::reset() { @@ -293,14 +300,14 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { } -void dom_simplify_tactic::init(goal& g) { +bool dom_simplify_tactic::init(goal& g) { expr_ref_vector args(m); unsigned sz = g.size(); for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); expr_ref fml = mk_and(args); m_result.reset(); m_trail.reset(); - m_dominators.compile(fml); + return m_dominators.compile(fml); } void dom_simplify_tactic::simplify_goal(goal& g) { @@ -312,7 +319,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { change = false; // go forwards - init(g); + if (!init(g)) return; unsigned sz = g.size(); for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { expr_ref r = simplify(g.form(i)); @@ -329,7 +336,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { pop(scope_level()); // go backwards - init(g); + if (!init(g)) return; sz = g.size(); for (unsigned i = sz; !g.inconsistent() && i > 0; ) { --i; diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 25fb7c24f..6e5833cdb 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -45,14 +45,14 @@ private: void compute_post_order(); expr* intersect(expr* x, expr * y); - void compute_dominators(); + bool compute_dominators(); void extract_tree(); public: expr_dominators(ast_manager& m): m(m), m_root(m) {} - void compile(expr * e); - void compile(unsigned sz, expr * const* es); + bool compile(expr * e); + bool compile(unsigned sz, expr * const* es); tree_t const& get_tree() { return m_tree; } void reset(); @@ -115,7 +115,7 @@ private: void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } bool assert_expr(expr* f, bool sign) { m_scope_level++; return m_simplifier->assert_expr(f, sign); } - void init(goal& g); + bool init(goal& g); public: dom_simplify_tactic(ast_manager & m, dom_simplifier* s, params_ref const & p = params_ref()): From 755ca46df65209f275966886acc968ea02533992 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 12:15:41 +0100 Subject: [PATCH 25/67] adding bv_bounds tactic dominator style Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/bv_bounds_tactic.cpp | 58 +++++------------------------- 1 file changed, 9 insertions(+), 49 deletions(-) diff --git a/src/tactic/bv/bv_bounds_tactic.cpp b/src/tactic/bv/bv_bounds_tactic.cpp index 2d5eb216a..44f920840 100644 --- a/src/tactic/bv/bv_bounds_tactic.cpp +++ b/src/tactic/bv/bv_bounds_tactic.cpp @@ -560,7 +560,7 @@ namespace { bool is_bound(expr *e, expr*& v, interval& b) const { uint64 n; expr *lhs = 0, *rhs = 0; - unsigned sz; + unsigned sz = 0; if (m_bv.is_bv_ule(e, lhs, rhs)) { if (is_number(lhs, n, sz)) { // C ule x <=> x uge C @@ -689,25 +689,27 @@ namespace { } interval ctx, intr; - bool unchanged = false; + bool was_updated = true; if (b.is_full() && b.tight) { r = m.mk_true(); } else if (m_bound.find(t1, ctx)) { if (ctx.implies(b)) { r = m.mk_true(); - } else if (!b.intersect(ctx, intr)) { + } + else if (!b.intersect(ctx, intr)) { r = m.mk_false(); - } else if (m_propagate_eq && intr.is_singleton()) { + } + else if (m_propagate_eq && intr.is_singleton()) { r = m.mk_eq(t1, m_bv.mk_numeral(rational(intr.l, rational::ui64()), m.get_sort(t1))); } } else { - unchanged = true; + was_updated = false; } - CTRACE("bv", !unchanged, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); - if (sign && unchanged) + CTRACE("bv", was_updated, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << r << "\n";); + if (sign && was_updated) r = m.mk_not(r); } @@ -773,45 +775,6 @@ namespace { return false; } - virtual bool may_simplify(expr* t) { - if (m_bv.is_numeral(t)) - return false; - - while (m.is_not(t, t)); - - for (auto & v : m_bound) { - if (contains(t, v.m_key)) return true; - } - -#if 0 - expr_set* used_exprs = get_expr_vars(t); - for (map::iterator I = m_bound.begin(), E = m_bound.end(); I != E; ++I) { - if (contains(t, I->m_key)) return true; - if (I->m_value.is_singleton() && used_exprs->contains(I->m_key)) - return true; - } -#endif - - expr* t1; - interval b; - // skip common case: single bound constraint without any context for simplification - if (is_bound(t, t1, b)) { - return b.is_full() || m_bound.contains(t1); - } - - if (contains_bound(t)) { - return true; - } -#if 0 - expr_cnt* bounds = get_expr_bounds(t); - for (expr_cnt::iterator I = bounds->begin(), E = bounds->end(); I != E; ++I) { - if (I->m_value > 1 || m_bound.contains(I->m_key)) - return true; - } -#endif - return false; - } - virtual void pop(unsigned num_scopes) { TRACE("bv", tout << "pop: " << num_scopes << "\n";); if (m_scopes.empty()) @@ -838,9 +801,6 @@ namespace { return alloc(dom_bv_bounds_simplifier, m, m_params); } - virtual unsigned scope_level() const { - return m_scopes.size(); - } }; } From 690b17fc25d8b8bac8af63ae4788e37b29b20cee Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 6 Oct 2017 12:33:47 +0100 Subject: [PATCH 26/67] Removed Ubuntu x86 VSTS/CI build (not supported by VSTS anymore). --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 197928877..701556cc8 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Windows x86 | Windows x64 | Ubuntu x64 | Ubuntu x86 | Debian x64 | OSX | TravisCI | -| ----------- | ----------- | ---------- | ---------- | ---------- | --- | -------- | -[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![ubuntu-x86-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/6/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=6) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) +| Windows x86 | Windows x64 | Ubuntu x64 | Debian x64 | OSX | TravisCI | +| ----------- | ----------- | ---------- | ---------- | --- | -------- | +[![win32-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/4/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=4) | [![win64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/7/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=7) | [![ubuntu-x64-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/3/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=3) | [![debian-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/5/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=5) | [![osx-badge](https://cz3.visualstudio.com/_apis/public/build/definitions/bf14bcc7-ebd4-4240-812c-5972fa59e0ad/2/badge)](https://cz3.visualstudio.com/Z3/_build/index?definitionId=2) | [![Build Status](https://travis-ci.org/Z3Prover/z3.svg?branch=master)](https://travis-ci.org/Z3Prover/z3) [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang From d47aea398730634444bd31172fd2a04739a9efa7 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 6 Oct 2017 11:23:44 +0100 Subject: [PATCH 27/67] [TravisCI] Workaround slow unit test execution for Debug builds. Unit tests execute very slowly in Debug (i.e. unoptimized) builds. This causes TravisCI to terminate the job due to no console output being seen. To workaround this for the debug builds the tests are just compiled but not executed. To implement this the `RUN_UNIT_TESTS` environment variable now can take on the values `BUILD_ONLY`, `BUILD_AND_RUN`, and `SKIP` rather than `0` or `1`. --- .travis.yml | 11 ++++-- contrib/ci/README.md | 2 +- contrib/ci/scripts/ci_defaults.sh | 2 +- .../ci/scripts/test_z3_unit_tests_cmake.sh | 36 ++++++++++++++----- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50d63e593..ac00ef918 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,10 +22,17 @@ env: # 64-bit Clang 3.9 RelWithDebInfo - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo + # Debug builds + # + # Note the unit tests for the debug builds are compiled but **not** + # executed. This is because the debug build of unit tests takes a large + # amount of time to execute compared to the optimized builds. The hope is + # that just running the optimized unit tests is sufficient. + # # 64-bit GCC 5.4 Debug - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY # 64-bit Clang Debug - - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_16.04 C_COMPILER=/usr/bin/clang-3.9 CXX_COMPILER=/usr/bin/clang++-3.9 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY # 32-bit GCC 5.4 RelWithDebInfo - LINUX_BASE=ubuntu32_16.04 C_COMPILER=/usr/bin/gcc-5 CXX_COMPILER=/usr/bin/g++-5 TARGET_ARCH=i686 Z3_BUILD_TYPE=RelWithDebInfo diff --git a/contrib/ci/README.md b/contrib/ci/README.md index 2e117c8b1..e4c9aecfd 100644 --- a/contrib/ci/README.md +++ b/contrib/ci/README.md @@ -31,7 +31,7 @@ the future. * `NO_SUPPRESS_OUTPUT` - Don't suppress output of some commands (`0` or `1`) * `PYTHON_BINDINGS` - Build and test Python API bindings (`0` or `1`) * `RUN_SYSTEM_TESTS` - Run system tests (`0` or `1`) -* `RUN_UNIT_TESTS` - Run unit tests (`0` or `1`) +* `RUN_UNIT_TESTS` - Run unit tests (`BUILD_ONLY` or `BUILD_AND_RUN` or `SKIP`) * `TARGET_ARCH` - Target architecture (`x86_64` or `i686`) * `TEST_INSTALL` - Test running `install` target (`0` or `1`) * `UBSAN_BUILD` - Do [UndefinedBehaviourSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) build (`0` or `1`) diff --git a/contrib/ci/scripts/ci_defaults.sh b/contrib/ci/scripts/ci_defaults.sh index 2fb3fa52a..d8e9376d8 100644 --- a/contrib/ci/scripts/ci_defaults.sh +++ b/contrib/ci/scripts/ci_defaults.sh @@ -10,7 +10,7 @@ export JAVA_BINDINGS="${JAVA_BINDINGS:-1}" export NO_SUPPRESS_OUTPUT="${NO_SUPPRESS_OUTPUT:-0}" export PYTHON_BINDINGS="${PYTHON_BINDINGS:-1}" export RUN_SYSTEM_TESTS="${RUN_SYSTEM_TESTS:-1}" -export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}" +export RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-BUILD_AND_RUN}" export TARGET_ARCH="${TARGET_ARCH:-x86_64}" export TEST_INSTALL="${TEST_INSTALL:-1}" export UBSAN_BUILD="${UBSAN_BUILD:-0}" diff --git a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh b/contrib/ci/scripts/test_z3_unit_tests_cmake.sh index 666673328..e1c927f58 100755 --- a/contrib/ci/scripts/test_z3_unit_tests_cmake.sh +++ b/contrib/ci/scripts/test_z3_unit_tests_cmake.sh @@ -10,17 +10,35 @@ set -o pipefail : ${Z3_BUILD_DIR?"Z3_BUILD_DIR must be specified"} : ${RUN_UNIT_TESTS?"RUN_UNIT_TESTS must be specified"} -if [ "X${RUN_UNIT_TESTS}" != "X1" ]; then - echo "Skipping unit tests" - exit 0 -fi - # Set CMake generator args source ${SCRIPT_DIR}/set_generator_args.sh cd "${Z3_BUILD_DIR}" -# Build and run internal tests -cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" -# Run all tests that don't require arguments -run_quiet ./test-z3 /a +function build_unit_tests() { + # Build internal tests + cmake --build $(pwd) --target test-z3 "${GENERATOR_ARGS[@]}" +} + +function run_unit_tests() { + # Run all tests that don't require arguments + run_quiet ./test-z3 /a +} + +case "${RUN_UNIT_TESTS}" in + BUILD_AND_RUN) + build_unit_tests + run_unit_tests + ;; + BUILD_ONLY) + build_unit_tests + ;; + SKIP) + echo "RUN_UNIT_TESTS set to \"${RUN_UNIT_TESTS}\" so skipping build and run" + exit 0 + ;; + *) + echo "Error: RUN_UNIT_TESTS set to unhandled value \"${RUN_UNIT_TESTS}\"" + exit 1 + ;; +esac From 2519719d3f452eb2cbbaf0db822e58b671e4e74f Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 6 Oct 2017 11:30:06 +0100 Subject: [PATCH 28/67] Fix typo --- contrib/ci/scripts/set_generator_args.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/ci/scripts/set_generator_args.sh b/contrib/ci/scripts/set_generator_args.sh index 0ef7b76aa..a704c518b 100644 --- a/contrib/ci/scripts/set_generator_args.sh +++ b/contrib/ci/scripts/set_generator_args.sh @@ -1,4 +1,4 @@ -# This script should is intended to be included by other +# This script is intended to be included by other # scripts and should not be executed directly : ${Z3_CMAKE_GENERATOR?"Z3_CMAKE_GENERATOR must be specified"} From 0be28b66fe3319be01492a0391514727e099916c Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 6 Oct 2017 11:48:20 +0100 Subject: [PATCH 29/67] [TravisCI] Update out of date `README.md` file. --- contrib/ci/README.md | 46 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/contrib/ci/README.md b/contrib/ci/README.md index e4c9aecfd..99bbcd7a6 100644 --- a/contrib/ci/README.md +++ b/contrib/ci/README.md @@ -58,8 +58,9 @@ The `scripts/travis_ci_linux_entry_point.sh` script variables (if set) into the build using the `--build-arg` argument of the `docker run` command. -If an environemnt variable is not set a defaults value is used which can be -found in `Dockerfiles/z3_build.Dockerfile`. +The default values of the configuration environment variables +can be found in +[`scripts/ci_defaults.sh`](scripts/ci_defaults.sh). #### Linux specific configuration variables @@ -67,8 +68,9 @@ found in `Dockerfiles/z3_build.Dockerfile`. #### Reproducing a build locally -A build can be reproduced locally by using the `scripts/travis_ci_linux_entry_point.sh` -script and setting the appropriate environment variable. +A build can be reproduced locally by using the +`scripts/travis_ci_linux_entry_point.sh` script and setting the appropriate +environment variable. For example lets say we wanted to reproduce the build below. @@ -104,11 +106,43 @@ feature might be removed in the future. It may be better to just build the base image once (outside of TravisCI), upload it to [DockerHub](https://hub.docker.com/) and have the build pull down the pre-built -image everytime. +image every time. An [organization](https://hub.docker.com/u/z3prover/) has been created on DockerHub for this. ### macOS -Not yet implemented. +For macOS we execute directly on TravisCI's macOS environment. The entry point +for the TravisCI builds is the +[`scripts/travis_ci_osx_entry_point.sh`](scripts/travis_ci_osx_entry_point.sh) +scripts. + +#### macOS specific configuration variables + +* `MACOS_SKIP_DEPS_UPDATE` - If set to `1` installing the necessary build dependencies + is skipped. This is useful for local testing if the dependencies are already installed. +* `MACOS_UPDATE_CMAKE` - If set to `1` the installed version of CMake will be upgraded. + +#### Reproducing a build locally + +To reproduce a build (e.g. like the one shown below) + +```yaml +- os: osx + osx_image: xcode8.3 + # Note: Apple Clang does not support OpenMP + env: Z3_BUILD_TYPE=RelWithDebInfo USE_OPENMP=0 +``` + +Run the following: + +```bash +TRAVIS_BUILD_DIR=$(pwd) \ +Z3_BUILD_TYPE=RelWithDebInfo \ +USE_OPEN_MP=0 \ +contrib/ci/scripts/travis_ci_osx_entry_point.sh +``` + +Note this assumes that the current working directory is the root of the Z3 +git repository. From 50042ab6388f5bd4bb7b8ba23622b96b7ef59131 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 6 Oct 2017 13:00:09 +0100 Subject: [PATCH 30/67] removed unused variables --- src/ast/fpa/fpa2bv_converter.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index f09ddcd42..13a7599a9 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1180,8 +1180,6 @@ void fpa2bv_converter::mk_abs(sort * s, expr_ref & x, expr_ref & result) { void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); expr * x = args[0], * y = args[1]; @@ -1227,8 +1225,6 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); expr * x = args[0], *y = args[1]; @@ -3081,8 +3077,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * mk_is_nan(x, x_is_nan); sort * fp_srt = m.get_sort(x); - unsigned ebits = m_util.get_ebits(fp_srt); - unsigned sbits = m_util.get_sbits(fp_srt); expr_ref unspec(m); mk_to_ieee_bv_unspecified(f, num, args, unspec); From 2634be01aa0c615e3b8b1362ce317f783b7109fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 13:43:01 +0100 Subject: [PATCH 31/67] adding backwards pass Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 35 +++++++++++++++++-------- src/tactic/core/dom_simplify_tactic.h | 3 ++- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index d38324db9..da704bd0b 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -281,17 +281,28 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { }; expr_ref_vector args(m); - for (expr * arg : *e) { - for (expr * child : tree(arg)) { - if (is_subexpr_arg(child, arg)) { - simplify(child); - } - } - r = simplify(arg); - args.push_back(r); - if (!assert_expr(simplify(arg), !is_and)) { - r = is_and ? m.mk_false() : m.mk_true(); - return r; + if (m_forward) { + for (expr * arg : *e) { +#define _SIMP_ARG(arg) \ + for (expr * child : tree(arg)) { \ + if (is_subexpr_arg(child, arg)) { \ + simplify(child); \ + } \ + } \ + r = simplify(arg); \ + args.push_back(r); \ + if (!assert_expr(simplify(arg), !is_and)) { \ + r = is_and ? m.mk_false() : m.mk_true(); \ + return r; \ + } + _SIMP_ARG(arg); + } + } + else { + for (unsigned i = e->get_num_args(); i > 0; ) { + --i; + expr* arg = e->get_arg(i); + _SIMP_ARG(arg); } } pop(scope_level() - old_lvl); @@ -319,6 +330,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { change = false; // go forwards + m_forward = true; if (!init(g)) return; unsigned sz = g.size(); for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { @@ -336,6 +348,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { pop(scope_level()); // go backwards + m_forward = false; if (!init(g)) return; sz = g.size(); for (unsigned i = sz; !g.inconsistent() && i > 0; ) { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 6e5833cdb..581d40cd0 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -96,6 +96,7 @@ private: unsigned m_max_depth; ptr_vector m_empty; obj_pair_map m_subexpr_cache; + bool m_forward; expr_ref simplify(expr* t); expr_ref simplify_ite(app * ite); @@ -122,7 +123,7 @@ public: 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_scope_level(0), m_depth(0), m_max_depth(1024), m_forward(true) {} virtual ~dom_simplify_tactic() {} From 9aa6386be94e96651b5c12065cb95a9e4dea74b8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 6 Oct 2017 15:27:16 +0100 Subject: [PATCH 32/67] fix debug build --- src/util/lp/indexed_vector_instances.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/lp/indexed_vector_instances.cpp b/src/util/lp/indexed_vector_instances.cpp index ee078f021..79c3ee1a1 100644 --- a/src/util/lp/indexed_vector_instances.cpp +++ b/src/util/lp/indexed_vector_instances.cpp @@ -33,6 +33,7 @@ template void indexed_vector::resize(unsigned int); template void indexed_vector::set_value(const mpq&, unsigned int); template void indexed_vector::set_value(const unsigned&, unsigned int); #ifdef Z3DEBUG +template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector >::is_OK() const; From ba8bff76ae9a68bef78c88913cbc2c62a193b299 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 6 Oct 2017 15:52:01 +0100 Subject: [PATCH 33/67] [TravisCI] Modify Debug configuration that I forgot to change with `RUN_UNIT_TESTS=BUILD_ONLY`. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ac00ef918..81ddefb8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -64,7 +64,7 @@ env: # 64-bit GCC 4.8 RelWithDebInfo - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=RelWithDebInfo # 64-bit GCC 4.8 Debug - - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug + - LINUX_BASE=ubuntu_14.04 C_COMPILER=/usr/bin/gcc-4.8 CXX_COMPILER=/usr/bin/g++-4.8 TARGET_ARCH=x86_64 Z3_BUILD_TYPE=Debug RUN_UNIT_TESTS=BUILD_ONLY # macOS (a.k.a OSX) support matrix: From c3f615dbfcf1436a142d1112598f358ed6c27bbd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 16:03:43 +0100 Subject: [PATCH 34/67] reverse arguments Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index da704bd0b..67b039814 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -291,7 +291,7 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { } \ r = simplify(arg); \ args.push_back(r); \ - if (!assert_expr(simplify(arg), !is_and)) { \ + if (!assert_expr(r, !is_and)) { \ r = is_and ? m.mk_false() : m.mk_true(); \ return r; \ } @@ -304,6 +304,7 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { expr* arg = e->get_arg(i); _SIMP_ARG(arg); } + args.reverse(); } pop(scope_level() - old_lvl); r = is_and ? mk_and(args) : mk_or(args); @@ -338,6 +339,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { r = m.mk_false(); } + CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); change |= r != g.form(i); proof* new_pr = 0; if (g.proofs_enabled()) { @@ -358,6 +360,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { r = m.mk_false(); } change |= r != g.form(i); + CTRACE("simplify", r != g.form(i), tout << r << " " << mk_pp(g.form(i), m) << "\n";); proof* new_pr = 0; if (g.proofs_enabled()) { new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); From 31c6b3eb5b94053c8c40f2939ad429c31471edaa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Oct 2017 16:07:25 +0100 Subject: [PATCH 35/67] fix leak Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 4 ++++ src/tactic/core/dom_simplify_tactic.h | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 67b039814..99f83799b 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -152,6 +152,10 @@ void expr_dominators::reset() { // ----------------------- // dom_simplify_tactic +dom_simplify_tactic::~dom_simplify_tactic() { + dealloc(m_simplifier); +} + tactic * dom_simplify_tactic::translate(ast_manager & m) { return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 581d40cd0..c1660a941 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -83,8 +83,6 @@ class dom_simplifier { }; class dom_simplify_tactic : public tactic { -public: -private: ast_manager& m; dom_simplifier* m_simplifier; params_ref m_params; @@ -126,7 +124,7 @@ public: m_scope_level(0), m_depth(0), m_max_depth(1024), m_forward(true) {} - virtual ~dom_simplify_tactic() {} + virtual ~dom_simplify_tactic(); virtual tactic * translate(ast_manager & m); virtual void updt_params(params_ref const & p) {} From 1d12a9c86de07feafe1261fa52b8248fe1d494ef Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 6 Oct 2017 18:19:37 +0100 Subject: [PATCH 36/67] dom_simplifier: fix dominator computation --- src/tactic/core/dom_simplify_tactic.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 99f83799b..16d8500a4 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -95,17 +95,17 @@ bool expr_dominators::compute_dominators() { for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; - SASSERT(!p.empty()); expr * new_idom = 0, *idom2 = 0; - for (unsigned j = 0; j < p.size(); ++j) { - if (!new_idom) { - m_doms.find(p[j], new_idom); - } - else if (m_doms.find(p[j], idom2)) { - new_idom = intersect(new_idom, idom2); + for (auto& pred : p) { + if (m_doms.contains(pred)) { + new_idom = !new_idom ? pred : intersect(new_idom, pred); } } - if (new_idom && (!m_doms.find(child, idom2) || idom2 != new_idom)) { + if (!new_idom) { + m_doms.insert(child, p[0]); + change = true; + } + else if (!m_doms.find(child, idom2) || idom2 != new_idom) { m_doms.insert(child, new_idom); change = true; } From a18236bc7f2a9037ccd1d7d078cb54c132328474 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 00:07:53 +0100 Subject: [PATCH 37/67] have quantifier equality take names into account Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 3 ++ src/ast/expr_abstract.cpp | 9 ++++ src/ast/expr_substitution.cpp | 7 +++ src/ast/expr_substitution.h | 3 ++ src/tactic/core/dom_simplify_tactic.cpp | 65 ++++++++++++++++++++----- src/tactic/core/dom_simplify_tactic.h | 5 +- 6 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index c98307ee0..cac12413e 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -471,6 +471,9 @@ bool compare_nodes(ast const * n1, ast const * n2) { compare_arrays(to_quantifier(n1)->get_decl_sorts(), to_quantifier(n2)->get_decl_sorts(), to_quantifier(n1)->get_num_decls()) && + compare_arrays(to_quantifier(n1)->get_decl_names(), + to_quantifier(n2)->get_decl_names(), + to_quantifier(n1)->get_num_decls()) && to_quantifier(n1)->get_expr() == to_quantifier(n2)->get_expr() && to_quantifier(n1)->get_weight() == to_quantifier(n2)->get_weight() && to_quantifier(n1)->get_num_patterns() == to_quantifier(n2)->get_num_patterns() && diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index 46682eed6..43035e203 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -19,6 +19,7 @@ Notes: #include "ast/expr_abstract.h" #include "util/map.h" +#include "ast/ast_pp.h" void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { @@ -109,6 +110,9 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { expr_abstractor abs(m); abs(base, num_bound, bound, n, result); + TRACE("expr_abstract", + tout << expr_ref(n, m) << "\n"; + tout << result << "\n";); } expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* const* bound, expr* n) { @@ -123,6 +127,11 @@ expr_ref mk_quantifier(bool is_forall, ast_manager& m, unsigned num_bound, app* } result = m.mk_quantifier(is_forall, num_bound, sorts.c_ptr(), names.c_ptr(), result); } + TRACE("expr_abstract", + tout << expr_ref(n, m) << "\n"; + for (unsigned i = 0; i < num_bound; ++i) tout << expr_ref(bound[i], m) << " "; + tout << "\n"; + tout << result << "\n";); return result; } diff --git a/src/ast/expr_substitution.cpp b/src/ast/expr_substitution.cpp index 149a59ce5..3ce038250 100644 --- a/src/ast/expr_substitution.cpp +++ b/src/ast/expr_substitution.cpp @@ -56,6 +56,13 @@ expr_substitution::~expr_substitution() { reset(); } +std::ostream& expr_substitution::display(std::ostream& out) { + for (auto & kv : m_subst) { + out << expr_ref(kv.m_key, m()) << " |-> " << expr_ref(kv.m_value, m()) << "\n"; + } + return out; +} + void expr_substitution::insert(expr * c, expr * def, proof * def_pr, expr_dependency * def_dep) { obj_map::obj_map_entry * entry = m_subst.insert_if_not_there2(c, 0); if (entry->get_data().m_value == 0) { diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index d360356eb..90154d163 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -50,6 +50,8 @@ public: bool contains(expr * s); void reset(); void cleanup(); + + std::ostream& display(std::ostream& out); }; class scoped_expr_substitution { @@ -84,6 +86,7 @@ public: bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); } bool contains(expr * s) { return m_subst.contains(s); } void cleanup() { m_subst.cleanup(); } + std::ostream& display(std::ostream& out) { return m_subst.display(out); } }; #endif diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 99f83799b..60207e823 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -91,23 +91,42 @@ bool expr_dominators::compute_dominators() { unsigned iterations = 1; while (change) { change = false; + TRACE("simplify", + for (auto & kv : m_doms) { + tout << expr_ref(kv.m_key, m) << " |-> " << expr_ref(kv.m_value, m) << "\n"; + }); + SASSERT(m_post2expr.empty() || m_post2expr.back() == e); for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; SASSERT(!p.empty()); - expr * new_idom = 0, *idom2 = 0; - for (unsigned j = 0; j < p.size(); ++j) { - if (!new_idom) { - m_doms.find(p[j], new_idom); - } - else if (m_doms.find(p[j], idom2)) { - new_idom = intersect(new_idom, idom2); - } + if (p.size() == 1) { + if (!m_doms.contains(child)) { + m_doms.insert(child, p[0]); + change = true; + } } - if (new_idom && (!m_doms.find(child, idom2) || idom2 != new_idom)) { - m_doms.insert(child, new_idom); - change = true; + else { + expr * new_idom = 0, *idom2 = 0; + for (unsigned j = 0; j < p.size(); ++j) { + if (!new_idom) { + m_doms.find(p[j], new_idom); + } + else if (m_doms.find(p[j], idom2)) { + new_idom = intersect(new_idom, idom2); + } + } + if (!new_idom) { + m_doms.insert(child, p[0]); + TRACE("simplify", tout << expr_ref(child, m) << " |-> " << expr_ref(p[0], m) << "\n";); + change = true; + } + else if (!m_doms.find(child, idom2) || idom2 != new_idom) { + m_doms.insert(child, new_idom); + TRACE("simplify", tout << expr_ref(child, m) << " |-> " << expr_ref(new_idom, m) << "\n";); + change = true; + } } } iterations *= 2; @@ -130,6 +149,7 @@ bool expr_dominators::compile(expr * e) { compute_post_order(); if (!compute_dominators()) return false; extract_tree(); + TRACE("simplify", display(tout);); return true; } @@ -147,6 +167,22 @@ void expr_dominators::reset() { m_root.reset(); } +std::ostream& expr_dominators::display(std::ostream& out) { + return display(out, 0, m_root); +} + +std::ostream& expr_dominators::display(std::ostream& out, unsigned indent, expr* r) { + for (unsigned i = 0; i < indent; ++i) out << " "; + out << expr_ref(r, m); + if (m_tree.contains(r)) { + for (expr* child : m_tree[r]) { + if (child != r) + display(out, indent + 1, child); + } + } + out << "\n"; + return out; +} // ----------------------- @@ -200,7 +236,6 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { simplify(child); } } - pop(scope_level() - old_lvl); expr_ref new_t = simplify(t); if (!assert_expr(new_c, true)) { @@ -230,6 +265,8 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr_ref dom_simplify_tactic::simplify(expr * e0) { expr_ref r(m); expr* e = 0; + + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); if (!m_result.find(e0, e)) { e = e0; } @@ -254,7 +291,9 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { if (is_app(e)) { m_args.reset(); for (expr* arg : *to_app(e)) { - m_args.push_back(get_cached(arg)); // TBD is cache really applied to all sub-terms? + r = get_cached(arg); + (*m_simplifier)(r); + m_args.push_back(r); } r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr()); } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index c1660a941..d99f799b4 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -48,6 +48,8 @@ private: bool compute_dominators(); void extract_tree(); + std::ostream& display(std::ostream& out, unsigned indent, expr* r); + public: expr_dominators(ast_manager& m): m(m), m_root(m) {} @@ -55,7 +57,8 @@ public: bool compile(unsigned sz, expr * const* es); tree_t const& get_tree() { return m_tree; } void reset(); - + + std::ostream& display(std::ostream& out); }; class dom_simplifier { From 76c309a595639cbbde974f8efe2b42f24a9d7e8f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 00:20:58 +0100 Subject: [PATCH 38/67] disable caching of simplifier when applied to direct arguments of terms. Caching is only valid when applied to dominator children Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 31 +++++++++++++------------ src/tactic/core/dom_simplify_tactic.h | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 830d44c7a..1bd685bb1 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -101,7 +101,8 @@ bool expr_dominators::compute_dominators() { expr * child = m_post2expr[i]; ptr_vector const& p = m_parents[child]; expr * new_idom = 0, *idom2 = 0; - for (auto& pred : p) { + + for (expr * pred : p) { if (m_doms.contains(pred)) { new_idom = !new_idom ? pred : intersect(new_idom, pred); } @@ -209,31 +210,31 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr * c = 0, *t = 0, *e = 0; VERIFY(m.is_ite(ite, c, t, e)); unsigned old_lvl = scope_level(); - expr_ref new_c = simplify(c); + expr_ref new_c = simplify(c, false); if (m.is_true(new_c)) { - r = simplify(t); + r = simplify(t, false); } else if (m.is_false(new_c) || !assert_expr(new_c, false)) { - r = simplify(e); + r = simplify(e, false); } else { for (expr * child : tree(ite)) { if (is_subexpr(child, t) && !is_subexpr(child, e)) { - simplify(child); + simplify(child, true); } } pop(scope_level() - old_lvl); - expr_ref new_t = simplify(t); + expr_ref new_t = simplify(t, false); if (!assert_expr(new_c, true)) { return new_t; } for (expr * child : tree(ite)) { if (is_subexpr(child, e) && !is_subexpr(child, t)) { - simplify(child); + simplify(child, true); } } pop(scope_level() - old_lvl); - expr_ref new_e = simplify(e); + expr_ref new_e = simplify(e, false); if (c == new_c && t == new_t && e == new_e) { r = ite; } @@ -248,7 +249,7 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { return r; } -expr_ref dom_simplify_tactic::simplify(expr * e0) { +expr_ref dom_simplify_tactic::simplify(expr * e0, bool cache_result) { expr_ref r(m); expr* e = 0; @@ -272,7 +273,7 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { } else { for (expr * child : tree(e)) { - simplify(child); + simplify(child, true); } if (is_app(e)) { m_args.reset(); @@ -288,7 +289,7 @@ expr_ref dom_simplify_tactic::simplify(expr * e0) { } } (*m_simplifier)(r); - cache(e0, r); + if (cache_result) cache(e0, r); TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); --m_depth; m_subexpr_cache.reset(); @@ -315,10 +316,10 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { #define _SIMP_ARG(arg) \ for (expr * child : tree(arg)) { \ if (is_subexpr_arg(child, arg)) { \ - simplify(child); \ + simplify(child, true); \ } \ } \ - r = simplify(arg); \ + r = simplify(arg, false); \ args.push_back(r); \ if (!assert_expr(r, !is_and)) { \ r = is_and ? m.mk_false() : m.mk_true(); \ @@ -364,7 +365,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { if (!init(g)) return; unsigned sz = g.size(); for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { - expr_ref r = simplify(g.form(i)); + expr_ref r = simplify(g.form(i), true); if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { r = m.mk_false(); } @@ -384,7 +385,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { sz = g.size(); for (unsigned i = sz; !g.inconsistent() && i > 0; ) { --i; - expr_ref r = simplify(g.form(i)); + expr_ref r = simplify(g.form(i), true); if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { r = m.mk_false(); } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index d99f799b4..e79777215 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -99,7 +99,7 @@ class dom_simplify_tactic : public tactic { obj_pair_map m_subexpr_cache; bool m_forward; - expr_ref simplify(expr* t); + expr_ref simplify(expr* t, bool cache); expr_ref simplify_ite(app * ite); expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); } expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); } From 7e4f5322023ddf5d1a4ae485d710c4f8c59a65f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 00:37:44 +0100 Subject: [PATCH 39/67] fix build by including mk_pp Signed-off-by: Nikolaj Bjorner --- src/ast/expr_substitution.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ast/expr_substitution.cpp b/src/ast/expr_substitution.cpp index 3ce038250..f9333c443 100644 --- a/src/ast/expr_substitution.cpp +++ b/src/ast/expr_substitution.cpp @@ -16,8 +16,9 @@ Author: Notes: --*/ -#include "ast/expr_substitution.h" #include "util/ref_util.h" +#include "ast/expr_substitution.h" +#include "ast/ast_pp.h" typedef obj_map expr2proof; typedef obj_map expr2expr_dependency; @@ -58,7 +59,7 @@ expr_substitution::~expr_substitution() { std::ostream& expr_substitution::display(std::ostream& out) { for (auto & kv : m_subst) { - out << expr_ref(kv.m_key, m()) << " |-> " << expr_ref(kv.m_value, m()) << "\n"; + out << mk_pp(kv.m_key, m()) << " |-> " << mk_pp(kv.m_value, m()) << "\n"; } return out; } From b898b077953c8e4a18d9b49567af37952e889eb8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 11:12:09 +0100 Subject: [PATCH 40/67] distinguish simplify_rec from simplify immediate argument Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 40 ++++++++++++++----------- src/tactic/core/dom_simplify_tactic.h | 3 +- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 1bd685bb1..366e1edb0 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -210,31 +210,31 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { expr * c = 0, *t = 0, *e = 0; VERIFY(m.is_ite(ite, c, t, e)); unsigned old_lvl = scope_level(); - expr_ref new_c = simplify(c, false); + expr_ref new_c = simplify_arg(c); if (m.is_true(new_c)) { - r = simplify(t, false); + r = simplify_arg(t); } else if (m.is_false(new_c) || !assert_expr(new_c, false)) { - r = simplify(e, false); + r = simplify_arg(e); } else { for (expr * child : tree(ite)) { if (is_subexpr(child, t) && !is_subexpr(child, e)) { - simplify(child, true); + simplify_rec(child); } } pop(scope_level() - old_lvl); - expr_ref new_t = simplify(t, false); + expr_ref new_t = simplify_arg(t); if (!assert_expr(new_c, true)) { return new_t; } for (expr * child : tree(ite)) { if (is_subexpr(child, e) && !is_subexpr(child, t)) { - simplify(child, true); + simplify_rec(child); } } pop(scope_level() - old_lvl); - expr_ref new_e = simplify(e, false); + expr_ref new_e = simplify_arg(e); if (c == new_c && t == new_t && e == new_e) { r = ite; } @@ -249,7 +249,15 @@ expr_ref dom_simplify_tactic::simplify_ite(app * ite) { return r; } -expr_ref dom_simplify_tactic::simplify(expr * e0, bool cache_result) { +expr_ref dom_simplify_tactic::simplify_arg(expr * e) { + expr_ref r(m); + r = get_cached(e); + (*m_simplifier)(r); + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e, m) << " -> " << r << "\n";); + return r; +} + +expr_ref dom_simplify_tactic::simplify_rec(expr * e0) { expr_ref r(m); expr* e = 0; @@ -273,14 +281,12 @@ expr_ref dom_simplify_tactic::simplify(expr * e0, bool cache_result) { } else { for (expr * child : tree(e)) { - simplify(child, true); + simplify_rec(child); } if (is_app(e)) { m_args.reset(); for (expr* arg : *to_app(e)) { - r = get_cached(arg); - (*m_simplifier)(r); - m_args.push_back(r); + m_args.push_back(simplify_arg(arg)); } r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr()); } @@ -289,7 +295,7 @@ expr_ref dom_simplify_tactic::simplify(expr * e0, bool cache_result) { } } (*m_simplifier)(r); - if (cache_result) cache(e0, r); + cache(e0, r); TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); --m_depth; m_subexpr_cache.reset(); @@ -316,10 +322,10 @@ expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { #define _SIMP_ARG(arg) \ for (expr * child : tree(arg)) { \ if (is_subexpr_arg(child, arg)) { \ - simplify(child, true); \ + simplify_rec(child); \ } \ } \ - r = simplify(arg, false); \ + r = simplify_arg(arg); \ args.push_back(r); \ if (!assert_expr(r, !is_and)) { \ r = is_and ? m.mk_false() : m.mk_true(); \ @@ -365,7 +371,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { if (!init(g)) return; unsigned sz = g.size(); for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { - expr_ref r = simplify(g.form(i), true); + expr_ref r = simplify_rec(g.form(i)); if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { r = m.mk_false(); } @@ -385,7 +391,7 @@ void dom_simplify_tactic::simplify_goal(goal& g) { sz = g.size(); for (unsigned i = sz; !g.inconsistent() && i > 0; ) { --i; - expr_ref r = simplify(g.form(i), true); + expr_ref r = simplify_rec(g.form(i)); if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { r = m.mk_false(); } diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index e79777215..4f9851514 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -99,7 +99,8 @@ class dom_simplify_tactic : public tactic { obj_pair_map m_subexpr_cache; bool m_forward; - expr_ref simplify(expr* t, bool cache); + expr_ref simplify_rec(expr* t); + expr_ref simplify_arg(expr* t); expr_ref simplify_ite(app * ite); expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); } expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); } From deba7d4d6e74c2896b2f75aeeacc205618157f05 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 14:35:44 +0100 Subject: [PATCH 41/67] use idom for checking dominator relationships Signed-off-by: Nikolaj Bjorner --- src/tactic/core/dom_simplify_tactic.cpp | 24 ++++++++++++++++-------- src/tactic/core/dom_simplify_tactic.h | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 366e1edb0..3a6d55569 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -257,11 +257,14 @@ expr_ref dom_simplify_tactic::simplify_arg(expr * e) { return r; } +/** + \brief simplify e recursively. +*/ expr_ref dom_simplify_tactic::simplify_rec(expr * e0) { expr_ref r(m); expr* e = 0; - TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << "\n";); if (!m_result.find(e0, e)) { e = e0; } @@ -408,6 +411,12 @@ void dom_simplify_tactic::simplify_goal(goal& g) { SASSERT(scope_level() == 0); } +/** + \brief determine if a is dominated by b. + Walk the immediate dominators of a upwards until hitting b or a term that is deeper than b. + Save intermediary results in a cache to avoid recomputations. +*/ + bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { if (a == b) return true; @@ -416,14 +425,13 @@ bool dom_simplify_tactic::is_subexpr(expr * a, expr * b) { if (m_subexpr_cache.find(a, b, r)) return r; - for (expr * e : tree(b)) { - if (is_subexpr(a, e)) { - m_subexpr_cache.insert(a, b, true); - return true; - } + if (get_depth(a) >= get_depth(b)) { + return false; } - m_subexpr_cache.insert(a, b, false); - return false; + SASSERT(a != idom(a) && get_depth(idom(a)) > get_depth(a)); + r = is_subexpr(idom(a), b); + m_subexpr_cache.insert(a, b, r); + return r; } ptr_vector const & dom_simplify_tactic::tree(expr * e) { diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 4f9851514..79bc9728c 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -57,6 +57,7 @@ public: bool compile(unsigned sz, expr * const* es); tree_t const& get_tree() { return m_tree; } void reset(); + expr* idom(expr *e) const { return m_doms[e]; } std::ostream& display(std::ostream& out); }; @@ -113,6 +114,7 @@ class dom_simplify_tactic : public tactic { void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } ptr_vector const & tree(expr * e); + expr* idom(expr *e) const { return m_dominators.idom(e); } unsigned scope_level() { return m_scope_level; } void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } From 6b88446ee804c8336aa11026344d46f2e0aee87e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 7 Oct 2017 19:02:06 +0100 Subject: [PATCH 42/67] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 448 +++++++++++++++++++++++++++---------- src/sat/ba_solver.h | 14 +- src/sat/sat_drat.cpp | 3 +- src/util/sorting_network.h | 6 +- 4 files changed, 349 insertions(+), 122 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a4275f804..0de5af885 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -221,7 +221,7 @@ namespace sat { if (c.lit() != null_literal && c.lit().sign() == is_true) { c.negate(); } - TRACE("sat", display(tout << "init watch: ", c, true);); + TRACE("ba", display(tout << "init watch: ", c, true);); SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); // put the non-false literals into the head. @@ -293,7 +293,7 @@ namespace sat { void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; - TRACE("sat", display(tout, c, true); ); + TRACE("ba", display(tout, c, true); ); SASSERT(validate_conflict(c)); if (c.is_xor() && value(lit) == l_true) lit.neg(); SASSERT(value(lit) == l_false); @@ -312,7 +312,7 @@ namespace sat { default: m_stats.m_num_propagations++; m_num_propagations_since_pop++; - //TRACE("sat", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); + //TRACE("ba", tout << "#prop: " << m_stats.m_num_propagations << " - " << c.lit() << " => " << lit << "\n";); SASSERT(validate_unit_propagation(c, lit)); if (get_config().m_drat) { svector ps; @@ -333,25 +333,26 @@ namespace sat { void ba_solver::simplify(pb_base& p) { SASSERT(s().at_base_lvl()); if (p.lit() != null_literal && value(p.lit()) == l_false) { - TRACE("sat", tout << "pb: flip sign " << p << "\n";); + TRACE("ba", tout << "pb: flip sign " << p << "\n";); IF_VERBOSE(0, verbose_stream() << "sign is flipped " << p << "\n";); return; - init_watch(p, !p.lit().sign()); } bool nullify = p.lit() != null_literal && value(p.lit()) == l_true; if (nullify) { + IF_VERBOSE(10, display(verbose_stream() << "nullify tracking literal\n", p, true);); SASSERT(lvl(p.lit()) == 0); nullify_tracking_literal(p); + init_watch(p, true); } - SASSERT(p.lit() == null_literal || value(p.lit()) == l_undef); + SASSERT(p.lit() == null_literal || value(p.lit()) != l_false); unsigned true_val = 0, slack = 0, num_false = 0; for (unsigned i = 0; i < p.size(); ++i) { literal l = p.get_lit(i); if (s().was_eliminated(l.var())) { SASSERT(p.learned()); - remove_constraint(p); + remove_constraint(p, "contains eliminated"); return; } switch (value(l)) { @@ -362,64 +363,73 @@ namespace sat { } if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); + IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { - if (nullify) { + if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } } else if (true_val >= p.k()) { if (p.lit() != null_literal) { + IF_VERBOSE(10, display(verbose_stream() << "assign true literal ", p, true);); s().assign(p.lit(), justification()); } - remove_constraint(p); + remove_constraint(p, "is true"); } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { + display(std::cout << "assign false literal ", p, true); s().assign(~p.lit(), justification()); } else { IF_VERBOSE(0, verbose_stream() << "unsat during simplification\n";); s().set_conflict(justification()); } - remove_constraint(p); + remove_constraint(p, "is false"); } else if (slack + true_val == p.k()) { - literal_vector lits(p.literals()); + literal_vector lits(p.literals()); + display(std::cout << "replace", p, true); assert_unconstrained(p.lit(), lits); - remove_constraint(p); + remove_constraint(p, "is tight"); } else { + unsigned sz = p.size(); clear_watch(p); + unsigned j = 0; for (unsigned i = 0; i < sz; ++i) { literal l = p.get_lit(i); - if (value(l) != l_undef) { - --sz; - p.swap(i, sz); - --i; + if (value(l) == l_undef) { + if (i != j) p.swap(i, j); + ++j; } } + sz = j; + // _bad_id = p.id(); BADLOG(display(verbose_stream() << "simplify ", p, true)); + p.set_size(sz); p.set_k(p.k() - true_val); - BADLOG(display(verbose_stream() << "simplified ", p, true)); - // display(verbose_stream(), c, true); if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "is clause"); return; } - else if (p.lit() == null_literal) { + else if (p.lit() == null_literal || value(p.lit()) == l_true) { init_watch(p, true); } else { SASSERT(value(p.lit()) == l_undef); } + BADLOG(display(verbose_stream() << "simplified ", p, true); verbose_stream() << "\n"); + // display(verbose_stream(), c, true); + _bad_id = 11111111; SASSERT(p.well_formed()); if (p.is_pb()) simplify2(p.to_pb()); m_simplify_change = true; @@ -545,9 +555,10 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); - SASSERT(validate_watch(p)); + VERIFY(validate_watch(p, null_literal)); + // SASSERT(validate_watch(p, null_literal)); - TRACE("sat", display(tout << "init watch: ", p, true);); + TRACE("ba", display(tout << "init watch: ", p, true);); // slack is tight: if (slack + slack1 == bound) { @@ -602,9 +613,8 @@ namespace sat { friendly (and the overhead of backtracking has to be taken into account). */ lbool ba_solver::add_assign(pb& p, literal alit) { - BADLOG(display(verbose_stream() << "assign: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); SASSERT(!inconsistent()); unsigned sz = p.size(); unsigned bound = p.k(); @@ -635,8 +645,8 @@ namespace sat { return l_undef; } - validate_watch(p); - // SASSERT(validate_watch(p)); + VERIFY(validate_watch(p, null_literal)); + // SASSERT(validate_watch(p, null_literal)); SASSERT(index < num_watch); unsigned index1 = index + 1; @@ -658,7 +668,7 @@ namespace sat { watch_literal(p[j], p); p.swap(num_watch, j); add_index(p, num_watch, lit); - BADLOG(verbose_stream() << "add watch: " << lit << " num watch: " << num_watch << "\n"); + BADLOG(verbose_stream() << "add watch: " << lit << " num watch: " << num_watch << " max: " << m_a_max << " slack " << slack << "\n"); ++num_watch; } } @@ -671,10 +681,10 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); - validate_watch(p); + VERIFY(validate_watch(p, null_literal)); BADLOG(display(verbose_stream() << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); - TRACE("sat", tout << "conflict " << alit << "\n";); + TRACE("ba", tout << "conflict " << alit << "\n";); set_conflict(p, alit); return l_false; } @@ -696,7 +706,8 @@ namespace sat { // l must be true. // if (slack < bound + m_a_max) { - TRACE("sat", tout << p; for(auto j : m_pb_undef) tout << j << "\n";); + BADLOG(verbose_stream() << "slack " << slack << " " << bound << " " << m_a_max << "\n";); + TRACE("ba", tout << p << "\n"; for(auto j : m_pb_undef) tout << j << " "; tout << "\n";); for (unsigned index1 : m_pb_undef) { if (index1 == num_watch) { index1 = index; @@ -704,16 +715,16 @@ namespace sat { wliteral wl = p[index1]; literal lit = wl.second; SASSERT(value(lit) == l_undef); - BADLOG(verbose_stream() << "Assign " << lit << "\n"); if (slack < bound + wl.first) { + BADLOG(verbose_stream() << "Assign " << lit << " " << wl.first << "\n"); assign(p, lit); } } } - validate_watch(p); + VERIFY(validate_watch(p, alit)); // except that alit is still watched. - TRACE("sat", display(tout << "assign: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); BADLOG(verbose_stream() << "unwatch " << alit << " watch: " << p.num_watch() << " size: " << p.size() << " slack: " << p.slack() << " " << inconsistent() << "\n"); @@ -729,6 +740,11 @@ namespace sat { unwatch_literal(p[i].second, p); } p.set_num_watch(0); + // debug code: + DEBUG_CODE( + for (wliteral wl : p) { + VERIFY(!is_watched(wl.second, p)); + }); } void ba_solver::recompile(pb& p) { @@ -781,21 +797,21 @@ namespace sat { if (p.lit() != null_literal) { s().assign(p.lit(), justification()); } - remove_constraint(p); + remove_constraint(p, "recompiled to true"); return; } if (k == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); s().mk_clause(sz, lits.c_ptr(), p.learned()); - remove_constraint(p); + remove_constraint(p, "recompiled to clause"); return; } if (all_units) { literal_vector lits(sz, p.literals().c_ptr()); add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p); + remove_constraint(p, "recompiled to cardinality"); return; } @@ -816,12 +832,12 @@ namespace sat { literal_vector lits(p.literals()); unsigned k = (p.k() + p[0].first - 1) / p[0].first; add_at_least(p.lit(), lits, k, p.learned()); - remove_constraint(p); + remove_constraint(p, "simplified to cardinality"); } else if (p.lit() == null_literal) { for (wliteral wl : p) { if (p.k() > p.max_sum() - wl.first) { - TRACE("sat", + TRACE("ba", tout << "unit literal " << wl.second << "\n"; display(tout, p, true);); @@ -833,17 +849,21 @@ namespace sat { void ba_solver::display(std::ostream& out, pb const& p, bool values) const { if (p.lit() != null_literal) out << p.lit() << " == "; - if (p.lit() != null_literal && values) { + if (values) { out << "[watch: " << p.num_watch() << ", slack: " << p.slack() << "]"; + } + if (p.lit() != null_literal && values) { out << "@(" << value(p.lit()); if (value(p.lit()) != l_undef) { out << ":" << lvl(p.lit()); } out << "): "; } + unsigned i = 0; for (wliteral wl : p) { literal l = wl.second; unsigned w = wl.first; + if (i++ == p.num_watch()) out << " | "; if (w > 1) out << w << " * "; out << l; if (values) { @@ -888,7 +908,7 @@ namespace sat { if (x.lit() != null_literal && x.lit().sign() == is_true) { x.negate(); } - TRACE("sat", display(tout, x, true);); + TRACE("ba", display(tout, x, true);); unsigned sz = x.size(); unsigned j = 0; for (unsigned i = 0; i < sz && j < 2; ++i) { @@ -930,7 +950,7 @@ namespace sat { lbool ba_solver::add_assign(xor& x, literal alit) { // literal is assigned unsigned sz = x.size(); - TRACE("sat", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + TRACE("ba", tout << "assign: " << x.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); SASSERT(value(alit) != l_undef); @@ -1077,6 +1097,8 @@ namespace sat { static literal _debug_consequent = null_literal; static unsigned_vector _debug_var2position; +// #define DEBUG_CODE(_x_) _x_ + lbool ba_solver::resolve_conflict() { if (0 == m_num_propagations_since_pop) { return l_undef; @@ -1087,7 +1109,7 @@ namespace sat { m_bound = 0; literal consequent = s().m_not_l; justification js = s().m_conflict; - TRACE("sat", tout << consequent << " " << js << "\n"; s().display(tout);); + TRACE("ba", tout << consequent << " " << js << "\n";); m_conflict_lvl = s().get_max_lvl(consequent, js); if (consequent != null_literal) { consequent.neg(); @@ -1114,10 +1136,10 @@ namespace sat { } TRACE("sat_verbose", display(tout, m_A);); - TRACE("sat", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); + TRACE("ba", tout << "process consequent: " << consequent << " : "; s().display_justification(tout, js) << "\n";); SASSERT(offset > 0); - // DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); + DEBUG_CODE(justification2pb(js, consequent, offset, m_B);); if (_debug_conflict) { IF_VERBOSE(0, @@ -1180,7 +1202,7 @@ namespace sat { inc_bound(offset); inc_coeff(consequent, offset); get_antecedents(consequent, p, m_lemma); - TRACE("sat", display(tout, p, true); tout << m_lemma << "\n";); + TRACE("ba", display(tout, p, true); tout << m_lemma << "\n";); if (_debug_conflict) { verbose_stream() << consequent << " "; verbose_stream() << "antecedents: " << m_lemma << "\n"; @@ -1212,10 +1234,10 @@ namespace sat { DEBUG_CODE( active2pb(m_C); - //SASSERT(validate_resolvent()); + VERIFY(validate_resolvent()); m_A = m_C;); - TRACE("sat", display(tout << "conflict: ", m_A);); + TRACE("ba", display(tout << "conflict: ", m_A);); cut(); @@ -1268,9 +1290,9 @@ namespace sat { goto bail_out; } - SASSERT(validate_conflict(m_lemma, m_A)); + DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); - TRACE("sat", tout << m_lemma << "\n";); + TRACE("ba", tout << m_lemma << "\n";); if (get_config().m_drat) { svector ps; // TBD fill in @@ -1280,7 +1302,7 @@ namespace sat { s().m_lemma.reset(); s().m_lemma.append(m_lemma); for (unsigned i = 1; i < m_lemma.size(); ++i) { - CTRACE("sat", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); + CTRACE("ba", s().is_marked(m_lemma[i].var()), tout << "marked: " << m_lemma[i] << "\n";); s().mark(m_lemma[i].var()); } @@ -1470,7 +1492,7 @@ namespace sat { TRACE("sat_verbose", tout << "Mark: v" << v << "\n";); ++m_num_marks; if (_debug_conflict && _debug_consequent != null_literal && _debug_var2position[_debug_consequent.var()] < _debug_var2position[l.var()]) { - std::cout << "antecedent " << l << " is above consequent in stack\n"; + IF_VERBOSE(0, verbose_stream() << "antecedent " << l << " is above consequent in stack\n";); } } inc_coeff(l, offset); @@ -1493,7 +1515,7 @@ namespace sat { } ba_solver::ba_solver(): m_solver(0), m_lookahead(0), m_constraint_id(0) { - TRACE("sat", tout << this << "\n";); + TRACE("ba", tout << this << "\n";); } ba_solver::~ba_solver() { @@ -1525,6 +1547,7 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { + // display(std::cout << "add " << c->learned() << " " << c->id() << "\n", *c, true); literal_vector lits(c->literals()); if (c->learned()) { m_learned.push_back(c); @@ -1613,8 +1636,8 @@ namespace sat { */ bool ba_solver::propagate(literal l, ext_constraint_idx idx) { SASSERT(value(l) == l_true); - TRACE("sat", tout << l << " " << idx << "\n";); constraint& c = index2constraint(idx); + TRACE("ba", tout << l << "\n";); if (c.lit() != null_literal && l.var() == c.lit().var()) { init_watch(c, !l.sign()); return true; @@ -1709,7 +1732,7 @@ namespace sat { unsigned level = lvl(l); bool_var v = l.var(); SASSERT(js.get_kind() == justification::EXT_JUSTIFICATION); - TRACE("sat", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); + TRACE("ba", tout << l << ": " << js << "\n"; tout << s().m_trail << "\n";); unsigned num_marks = 0; unsigned count = 0; @@ -1776,7 +1799,7 @@ namespace sat { reset_parity(lit.var()); } m_parity_trail.reset(); - TRACE("sat", tout << r << "\n";); + TRACE("ba", tout << r << "\n";); } /** @@ -1791,8 +1814,29 @@ namespace sat { Then x is an explanation for l */ + + bool ba_solver::assigned_above(literal above, literal below) { + unsigned l = lvl(above); + SASSERT(l == lvl(below)); + if (l == 0) return false; + unsigned start = s().m_scopes[l-1].m_trail_lim; + literal_vector const& lits = s().m_trail; + +#if 0 + IF_VERBOSE(10, verbose_stream() << "level " << l << " scope level " << s().scope_lvl() << " tail lim start: " + << start << " size of lits: " << lits.size() << " num scopes " << s().m_scopes.size() << "\n";); +#endif + + for (unsigned sz = lits.size(); sz-- > start; ) { + if (lits[sz] == above) return true; + if (lits[sz] == below) return false; + } + UNREACHABLE(); + return false; + } + void ba_solver::get_antecedents(literal l, pb const& p, literal_vector& r) { - TRACE("sat", display(tout, p, true);); + TRACE("ba", display(tout << l << " level: " << s().scope_lvl() << " ", p, true);); SASSERT(p.lit() == null_literal || value(p.lit()) == l_true); if (p.lit() != null_literal) { @@ -1802,8 +1846,8 @@ namespace sat { unsigned k = p.k(); if (_debug_conflict) { - display(std::cout, p, true); - std::cout << "literal: " << l << " value: " << value(l) << " num-watch: " << p.num_watch() << " slack: " << p.slack() << "\n"; + IF_VERBOSE(0, display(verbose_stream(), p, true); + verbose_stream() << "literal: " << l << " value: " << value(l) << " num-watch: " << p.num_watch() << " slack: " << p.slack() << "\n";); } if (value(l) == l_false) { @@ -1830,6 +1874,8 @@ namespace sat { } } else { + // comes from a unit propagation + SASSERT(value(l) == l_true); unsigned coeff = 0, j = 0; for (; j < p.size(); ++j) { if (p[j].second == l) { @@ -1842,21 +1888,29 @@ namespace sat { if (j < p.num_watch()) { j = p.num_watch(); } - CTRACE("sat", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); + CTRACE("ba", coeff == 0, display(tout << l << " coeff: " << coeff << "\n", p, true);); if (_debug_conflict) { std::cout << "coeff " << coeff << "\n"; } SASSERT(coeff > 0); - unsigned slack = p.slack() - coeff; - j = std::max(j + 1, p.num_watch()); + unsigned slack = p.max_sum() - coeff; + // we need antecedents to be deeper than alit. for (; j < p.size(); ++j) { literal lit = p[j].second; unsigned w = p[j].first; - SASSERT(l_false == value(lit)); - if (slack + w < k) { + if (l_false != value(lit)) { + // skip + } + else if (lvl(lit) > lvl(l)) { + // skip + } + else if (lvl(lit) == lvl(l) && assigned_above(~lit, l)) { + // skip + } + else if (slack + w < k) { slack += w; } else { @@ -1908,7 +1962,7 @@ namespace sat { void ba_solver::get_antecedents(literal l, xor const& x, literal_vector& r) { if (x.lit() != null_literal) r.push_back(x.lit()); - // TRACE("sat", display(tout << l << " ", x, true);); + // TRACE("ba", display(tout << l << " ", x, true);); SASSERT(x.lit() == null_literal || value(x.lit()) == l_true); SASSERT(x[0].var() == l.var() || x[1].var() == l.var()); if (x[0].var() == l.var()) { @@ -1977,10 +2031,11 @@ namespace sat { } } - void ba_solver::remove_constraint(constraint& c) { + void ba_solver::remove_constraint(constraint& c, char const* reason) { + IF_VERBOSE(21, display(verbose_stream() << "remove " << reason << " ", c, true);); nullify_tracking_literal(c); clear_watch(c); - c.remove(); + c.set_removed(); m_constraint_removed = true; } @@ -2100,16 +2155,11 @@ namespace sat { } bool ba_solver::validate_watched_constraint(constraint const& c) const { - if (c.is_pb() && !validate_watch(c.to_pb())) { + if (c.is_pb() && !validate_watch(c.to_pb(), null_literal)) { return false; } if (c.lit() != null_literal && value(c.lit()) != l_true) return true; - if (c.lit() != null_literal && lvl(c.lit()) != 0) { - if (!is_watched(c.lit(), c) || !is_watched(~c.lit(), c)) { - UNREACHABLE(); - return false; - } - } + SASSERT(c.lit() == null_literal || lvl(c.lit()) == 0 || (is_watched(c.lit(), c) && is_watched(~c.lit(), c))); if (eval(c) == l_true) { return true; } @@ -2136,14 +2186,25 @@ namespace sat { return true; } - bool ba_solver::validate_watch(pb const& p) const { + bool ba_solver::validate_watch(pb const& p, literal alit) const { for (unsigned i = 0; i < p.size(); ++i) { literal l = p[i].second; - if (lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + if (l != alit && lvl(l) != 0 && is_watched(l, p) != i < p.num_watch()) { + IF_VERBOSE(0, display(verbose_stream(), p, true); + verbose_stream() << "literal " << l << " at position " << i << " " << is_watched(l, p) << "\n";); UNREACHABLE(); return false; } } + unsigned slack = 0; + for (unsigned i = 0; i < p.num_watch(); ++i) { + slack += p[i].first; + } + if (slack != p.slack()) { + IF_VERBOSE(0, display(verbose_stream(), p, true);); + UNREACHABLE(); + return false; + } return true; } @@ -2190,14 +2251,14 @@ namespace sat { } void ba_solver::gc_half(char const* st_name) { - TRACE("sat", tout << "gc\n";); + TRACE("ba", tout << "gc\n";); unsigned sz = m_learned.size(); unsigned new_sz = sz/2; unsigned removed = 0; for (unsigned i = new_sz; i < sz; i++) { constraint* c = m_learned[i]; if (!m_constraint_to_reinit.contains(c)) { - remove_constraint(*c); + remove_constraint(*c, "gc"); ++removed; } } @@ -2211,7 +2272,7 @@ namespace sat { // literal is assigned to false. unsigned sz = c.size(); unsigned bound = c.k(); - TRACE("sat", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); + TRACE("ba", tout << "assign: " << c.lit() << ": " << ~alit << "@" << lvl(~alit) << "\n";); SASSERT(0 < bound && bound <= sz); if (bound == sz) { @@ -2245,12 +2306,12 @@ namespace sat { // conflict if (bound != index && value(c[bound]) == l_false) { - TRACE("sat", tout << "conflict " << c[bound] << " " << alit << "\n";); + TRACE("ba", tout << "conflict " << c[bound] << " " << alit << "\n";); set_conflict(c, alit); return l_false; } - // TRACE("sat", tout << "no swap " << index << " " << alit << "\n";); + // TRACE("ba", tout << "no swap " << index << " " << alit << "\n";); // there are no literals to swap with, // prepare for unit propagation by swapping the false literal into // position bound. Then literals in positions 0..bound-1 have to be @@ -2319,7 +2380,7 @@ namespace sat { } } - void ba_solver::simplify() { + void ba_solver::simplify() { if (!s().at_base_lvl()) s().pop_to_base_level(); unsigned trail_sz; do { @@ -2340,7 +2401,7 @@ namespace sat { } while (m_simplify_change || trail_sz < s().init_trail_size()); - IF_VERBOSE(1, verbose_stream() << "(ba.simplify " + IF_VERBOSE(1, verbose_stream() << "(ba.simplify" << " :vars " << s().num_vars() - trail_sz << " :constraints " << m_constraints.size() << " :lemmas " << m_learned.size() @@ -2520,7 +2581,7 @@ namespace sat { void ba_solver::recompile(constraint& c) { if (c.id() == _bad_id) { - display(std::cout << "recompile\n", c, true); + IF_VERBOSE(0, display(verbose_stream() << "recompile\n", c, true);); } switch (c.tag()) { case card_t: @@ -2585,14 +2646,14 @@ namespace sat { } if (k == 0) { - remove_constraint(c); + remove_constraint(c, "recompiled to true"); return; } if (k == 1) { literal_vector lits(c.size(), c.begin()); s().mk_clause(lits.size(), lits.c_ptr(), c.learned()); - remove_constraint(c); + remove_constraint(c, "recompiled to clause"); return; } @@ -2600,13 +2661,13 @@ namespace sat { c.set_k(k); if (!all_units) { - TRACE("sat", tout << "replacing by pb: " << c << "\n";); + TRACE("ba", tout << "replacing by pb: " << c << "\n";); m_wlits.reset(); for (unsigned i = 0; i < sz; ++i) { m_wlits.push_back(wliteral(coeffs[i], c[i])); } literal root = c.lit(); - remove_constraint(c); + remove_constraint(c, "recompiled to pb"); add_pb_ge(root, m_wlits, k, c.learned()); } else { @@ -2634,6 +2695,7 @@ namespace sat { found = m_root_vars[c.get_lit(i).var()]; } if (!found) return; + //std::cout << "reroot " << c << "\n"; clear_watch(c); // this could create duplicate literals @@ -2671,11 +2733,12 @@ namespace sat { found_root |= l.var() == root.var(); } + //std::cout << "reroot " << c << "\n"; if (found_root) { split_root(c); c.negate(); split_root(c); - remove_constraint(c); + remove_constraint(c, "flush roots"); } else if (found_dup) { recompile(c); @@ -2755,12 +2818,13 @@ namespace sat { switch (c.tag()) { case card_t: case pb_t: { - if (lit != null_literal && + if (lit != null_literal && + value(lit) == l_undef && use_count(lit) == 1 && use_count(~lit) == 1 && get_num_non_learned_bin(lit) == 0 && get_num_non_learned_bin(~lit) == 0) { - remove_constraint(c); + remove_constraint(c, "unused def"); } break; } @@ -2790,7 +2854,7 @@ namespace sat { for (unsigned i = 0; i < c.size(); ++i) { bool_var v = c.get_lit(i).var(); if (s().was_eliminated(v)) { - remove_constraint(c); + remove_constraint(c, "contains eliminated var"); break; } s().set_external(v); @@ -2801,9 +2865,9 @@ namespace sat { } bool ba_solver::elim_pure(literal lit) { - if (value(lit) != l_undef) return false; - if (!m_cnstr_use_list[lit.index()].empty() && use_count(~lit) == 0 && - get_num_non_learned_bin(~lit) == 0) { + if (value(lit) == l_undef && !m_cnstr_use_list[lit.index()].empty() && + use_count(~lit) == 0 && get_num_non_learned_bin(~lit) == 0) { + IF_VERBOSE(10, verbose_stream() << "pure literal: " << lit << "\n";); s().assign(lit, justification()); return true; } @@ -2855,7 +2919,7 @@ namespace sat { clause_vector::iterator it2 = it; for (; it != end; ++it) { clause* c = *it; - if (c->was_removed()) { + if (c->was_removed() && s().can_delete(*c)) { s().detach_clause(*c); s().del_clause(*c); } @@ -2891,6 +2955,8 @@ namespace sat { for (; it != end; ++it) { constraint& c = *(*it); if (c.was_removed()) { + clear_watch(c); + nullify_tracking_literal(c); m_allocator.deallocate(c.obj_size(), &c); } else if (learned && !c.learned()) { @@ -2994,7 +3060,7 @@ namespace sat { if (s) { ++m_stats.m_num_pb_subsumes; p1.set_learned(false); - remove_constraint(*c); + remove_constraint(*c, "subsumed"); } } } @@ -3023,13 +3089,14 @@ namespace sat { SASSERT(c1.index() != c2.index()); if (subsumes(c1, c2, slit)) { if (slit.empty()) { - TRACE("sat", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); - remove_constraint(c2); + TRACE("ba", tout << "subsume cardinality\n" << c1.index() << ":" << c1 << "\n" << c2.index() << ":" << c2 << "\n";); + remove_constraint(c2, "subsumed"); ++m_stats.m_num_pb_subsumes; c1.set_learned(false); + std::cout << c1 << " subsumes " << c2 << "\n"; } else { - TRACE("sat", tout << "self subsume cardinality\n";); + TRACE("ba", tout << "self subsume cardinality\n";); IF_VERBOSE(0, verbose_stream() << "self-subsume cardinality is TBD\n"; verbose_stream() << c1 << "\n"; @@ -3059,15 +3126,16 @@ namespace sat { clause& c2 = it.curr(); if (!c2.was_removed() && subsumes(c1, c2, slit)) { if (slit.empty()) { - TRACE("sat", tout << "remove\n" << c1 << "\n" << c2 << "\n";); + TRACE("ba", tout << "remove\n" << c1 << "\n" << c2 << "\n";); removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; c1.set_learned(false); + std::cout << c1 << " subsumes " << c2 << "\n"; } else { IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); // remove literal slit from c2. - TRACE("sat", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); + TRACE("ba", tout << "TBD remove literals " << slit << " from " << c2 << "\n";); } } it.next(); @@ -3089,6 +3157,7 @@ namespace sat { // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_binary_non_learned_clause()) { c1.set_learned(false); + std::cout << c1 << " subsumes " << lit << " " << w.get_literal() << "\n"; } } else { @@ -3098,9 +3167,7 @@ namespace sat { ++it2; } } - if (it != it2) { - wlist.set_end(it2); - } + wlist.set_end(it2); } void ba_solver::subsumption(card& c1) { @@ -3138,7 +3205,7 @@ namespace sat { for (wliteral l : p1) { m_weights[l.second.index()] = 0; unmark_visited(l.second); - } + } } void ba_solver::clauses_modifed() {} @@ -3149,6 +3216,7 @@ namespace sat { \brief lit <=> conjunction of unconstrained lits */ void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { + std::cout << "assert unconstrained\n"; if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -3431,12 +3499,12 @@ namespace sat { } bool ba_solver::validate_unit_propagation(pb const& p, literal alit) const { - if (p.lit() != null_literal && value(p.lit()) != l_true) { + if (p.lit() != null_literal && value(p.lit()) != l_true) { return false; } unsigned sum = 0; - TRACE("sat", display(tout << "validate: " << alit << "\n", p, true);); + TRACE("ba", display(tout << "validate: " << alit << "\n", p, true);); for (wliteral wl : p) { literal lit = wl.second; lbool val = value(lit); @@ -3448,21 +3516,54 @@ namespace sat { } bool ba_solver::validate_unit_propagation(pb const& p, literal_vector const& r, literal alit) const { - unsigned sum = 0; // all elements of r are true, for (literal l : r) { if (value(l) != l_true) { + std::cout << "value of " << l << " is " << value(l) << "\n"; + display(std::cout, p, true); return false; } + if (value(alit) == l_true && lvl(l) > lvl(alit)) { + std::cout << "level of premise " << l << " is " << lvl(l) << "\n"; + std::cout << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; + display(std::cout, p, true); + return false; + } + // if (value(alit) == l_true && lvl(l) == lvl(alit)) { + // std::cout << "same level " << alit << " " << l << "\n"; + // } } // the sum of elements not in r or alit add up to less than k. + unsigned sum = 0; + // + // a*x + b*alit + c*r >= k + // sum a < k + // val(r) = false + // hence alit has to be true. for (wliteral wl : p) { literal lit = wl.second; - if (lit != alit && value(lit) != l_false && !r.contains(~lit)) { + if (lit != alit && !r.contains(~lit)) { sum += wl.first; } } - return sum < p.k(); + if (sum >= p.k()) { + std::cout << "sum is " << sum << " >= " << p.k() << "\n"; + display(std::cout, p, true); + std::cout << "id: " << p.id() << "\n"; + sum = 0; + for (wliteral wl : p) sum += wl.first; + std::cout << "overall sum " << sum << "\n"; + std::cout << "asserting literal: " << alit << "\n"; + std::cout << "reason: " << r << "\n"; + return false; + } + for (wliteral wl : p) { + if (alit == wl.second) { + return true; + } + } + std::cout << alit << " not found among literals\n"; + return false; } bool ba_solver::validate_unit_propagation(xor const& x, literal alit) const { @@ -3490,7 +3591,7 @@ namespace sat { val += coeff; } } - CTRACE("sat", val >= 0, active2pb(m_A); display(tout, m_A);); + CTRACE("ba", val >= 0, active2pb(m_A); display(tout, m_A);); return val < 0; } @@ -3627,12 +3728,12 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { + std::cout << *c << "\n"; lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); } unsigned glue = s().num_diff_levels(lits.size(), lits.c_ptr()); - c->set_glue(glue); } return c; @@ -3706,6 +3807,7 @@ namespace sat { // validate that m_A & m_B implies m_C bool ba_solver::validate_resolvent() { + return true; u_map coeffs; uint64 k = m_A.m_k + m_B.m_k; for (unsigned i = 0; i < m_A.m_lits.size(); ++i) { @@ -3745,7 +3847,6 @@ namespace sat { uint64 coeff; if (coeffs.find(lit.index(), coeff)) { if (coeff > m_C.m_coeffs[i] && m_C.m_coeffs[i] < m_C.m_k) { - IF_VERBOSE(0, verbose_stream() << i << ": " << m_C.m_coeffs[i] << " " << m_C.m_k << "\n";); goto violated; } coeffs.remove(lit.index()); @@ -3758,6 +3859,23 @@ namespace sat { return true; violated: + // last ditch effort by translating to SAT. + solver s0(s().m_params, s().rlimit()); + u_map translation; + literal l1 = translate_to_sat(s0, translation, m_A); + if (l1 == null_literal) return true; + literal l2 = translate_to_sat(s0, translation, m_B); + if (l2 == null_literal) return true; + ineq notC = negate(m_B); + literal l3 = translate_to_sat(s0, translation, notC); + if (l3 == null_literal) return true; + s0.assign(l1, justification()); + s0.assign(l2, justification()); + s0.assign(l3, justification()); + lbool is_sat = s0.check(); + TRACE("ba", s0.display(tout << "trying sat encoding");); + if (is_sat == l_false) return true; + IF_VERBOSE(0, display(verbose_stream(), m_A); display(verbose_stream(), m_B); @@ -3766,13 +3884,111 @@ namespace sat { verbose_stream() << to_literal(e.m_key) << ": " << e.m_value << "\n"; }); + UNREACHABLE(); return false; } + /** + \brief translate PB inequality to SAT formula. + */ + literal ba_solver::translate_to_sat(solver& s, u_map& translation, ineq const& pb) { + SASSERT(pb.m_k > 0); + if (pb.m_lits.size() > 1) { + ineq a, b; + a.reset(pb.m_k); + b.reset(pb.m_k); + for (unsigned i = 0; i < pb.m_lits.size()/2; ++i) { + a.push(pb.m_lits[i], pb.m_coeffs[i]); + } + for (unsigned i = pb.m_lits.size()/2; i < pb.m_lits.size(); ++i) { + b.push(pb.m_lits[i], pb.m_coeffs[i]); + } + bool_var v = s.mk_var(); + literal lit(v, false); + literal_vector lits; + lits.push_back(~lit); + push_lit(lits, translate_to_sat(s, translation, a)); + push_lit(lits, translate_to_sat(s, translation, b)); + push_lit(lits, translate_to_sat(s, translation, a, b)); + s.mk_clause(lits); + return lit; + } + if (pb.m_coeffs[0] >= pb.m_k) { + return translate_to_sat(s, translation, pb.m_lits[0]); + } + else { + return null_literal; + } + } + + /* + \brief encode the case where Sum(a) >= k-1 & Sum(b) >= 1 \/ ... \/ Sum(a) >= 1 & Sum(b) >= k-1 + */ + literal ba_solver::translate_to_sat(solver& s, u_map& translation, ineq& a, ineq& b) { + uint64 k0 = a.m_k; + literal_vector lits; + for (unsigned k = 1; k < a.m_k - 1; ++k) { + a.m_k = k; b.m_k = k0 - k; + literal lit1 = translate_to_sat(s, translation, a); + literal lit2 = translate_to_sat(s, translation, b); + if (lit1 != null_literal && lit2 != null_literal) { + bool_var v = s.mk_var(); + literal lit(v, false); + s.mk_clause(~lit, lit1); + s.mk_clause(~lit, lit2); + lits.push_back(lit); + } + } + a.m_k = k0; + b.m_k = k0; + switch (lits.size()) { + case 0: return null_literal; + case 1: return lits[0]; + default: { + bool_var v = s.mk_var(); + literal lit(v, false); + lits.push_back(~lit); + s.mk_clause(lits); + return lit; + } + } + } + + literal ba_solver::translate_to_sat(solver& s, u_map& translation, literal lit) { + bool_var v; + if (!translation.find(lit.var(), v)) { + v = s.mk_var(); + translation.insert(lit.var(), v); + } + return literal(v, lit.sign()); + } + + ba_solver::ineq ba_solver::negate(ineq const& a) const { + ineq result; + uint64 sum = 0; + for (unsigned i = 0; i < a.m_lits.size(); ++i) { + result.push(~a.m_lits[i], a.m_coeffs[i]); + sum += a.m_coeffs[i]; + } + SASSERT(sum >= a.m_k + 1); + result.m_k = sum + 1 - a.m_k; + return result; + } + + void ba_solver::push_lit(literal_vector& lits, literal lit) { + if (lit != null_literal) { + lits.push_back(lit); + } + } + bool ba_solver::validate_conflict(literal_vector const& lits, ineq& p) { for (literal l : lits) { if (value(l) != l_false) { - TRACE("sat", tout << "literal " << l << " is not false\n";); + TRACE("ba", tout << "literal " << l << " is not false\n";); + return false; + } + if (!p.m_lits.contains(l)) { + TRACE("ba", tout << "lemma contains literal " << l << " not in inequality\n";); return false; } } @@ -3783,7 +3999,7 @@ namespace sat { value += coeff; } } - CTRACE("sat", value >= p.m_k, tout << "slack: " << value << " bound " << p.m_k << "\n"; + CTRACE("ba", value >= p.m_k, tout << "slack: " << value << " bound " << p.m_k << "\n"; display(tout, p); tout << lits << "\n";); return value < p.m_k; diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 88a81701a..360f276f2 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -79,7 +79,7 @@ namespace sat { void set_size(unsigned sz) { SASSERT(sz <= m_size); m_size = sz; } void update_literal(literal l) { m_lit = l; } bool was_removed() const { return m_removed; } - void remove() { m_removed = true; } + void set_removed() { m_removed = true; } void nullify_literal() { m_lit = null_literal; } unsigned glue() const { return m_glue; } void set_glue(unsigned g) { m_glue = g; } @@ -199,7 +199,7 @@ namespace sat { svector m_coeffs; uint64 m_k; void reset(uint64 k) { m_lits.reset(); m_coeffs.reset(); m_k = k; } - void push(literal l, unsigned c) { m_lits.push_back(l); m_coeffs.push_back(c); } + void push(literal l, uint64 c) { m_lits.push_back(l); m_coeffs.push_back(c); } }; solver* m_solver; @@ -286,7 +286,7 @@ namespace sat { void cleanup_constraints(); void cleanup_constraints(ptr_vector& cs, bool learned); void ensure_external(constraint const& c); - void remove_constraint(constraint& c); + void remove_constraint(constraint& c, char const* reason); // constraints constraint& index2constraint(size_t idx) const { return *reinterpret_cast(idx); } @@ -304,6 +304,7 @@ namespace sat { void nullify_tracking_literal(constraint& c); void set_conflict(constraint& c, literal lit); void assign(constraint& c, literal lit); + bool assigned_above(literal above, literal below); void get_antecedents(literal l, constraint const& c, literal_vector & r); bool validate_conflict(constraint const& c) const; bool validate_unit_propagation(constraint const& c, literal alit) const; @@ -402,8 +403,13 @@ namespace sat { bool validate_watch_literals() const; bool validate_watch_literal(literal lit) const; bool validate_watched_constraint(constraint const& c) const; - bool validate_watch(pb const& p) const; + bool validate_watch(pb const& p, literal alit) const; bool is_watching(literal lit, constraint const& c) const; + literal translate_to_sat(solver& s, u_map& translation, ineq const& pb); + literal translate_to_sat(solver& s, u_map& translation, ineq& a, ineq& b); + literal translate_to_sat(solver& s, u_map& translation, literal lit); + ineq negate(ineq const& a) const; + void push_lit(literal_vector& lits, literal lit); ineq m_A, m_B, m_C; void active2pb(ineq& p); diff --git a/src/sat/sat_drat.cpp b/src/sat/sat_drat.cpp index 0f1b578f1..d3864fd8b 100644 --- a/src/sat/sat_drat.cpp +++ b/src/sat/sat_drat.cpp @@ -272,7 +272,8 @@ namespace sat { void drat::verify(unsigned n, literal const* c) { if (!is_drup(n, c) && !is_drat(n, c)) { std::cout << "Verification failed\n"; - display(std::cout); + UNREACHABLE(); + //display(std::cout); TRACE("sat", tout << literal_vector(n, c) << "\n"; display(tout); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index ade66403d..ab0d69791 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -469,7 +469,9 @@ Notes: } literal mk_ordered_1(bool full, bool is_eq, unsigned n, literal const* xs) { - if (n <= 1 && !is_eq) return ctx.mk_true(); + if (n <= 1 && !is_eq) { + return ctx.mk_true(); + } if (n == 0) { return ctx.mk_false(); } @@ -477,6 +479,8 @@ Notes: return xs[0]; } + SASSERT(n > 1); + // y0 -> y1 // x0 -> y0 // x1 -> y1 From a5ecf87ab82c86b01eef01646b70fdcbb30b1f5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:32:38 +0100 Subject: [PATCH 43/67] fix #1288 Signed-off-by: Nikolaj Bjorner --- src/muz/rel/tbv.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 7475750db..69cc4819a 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -74,8 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { } tbv* tbv_manager::allocate(uint64 val) { tbv* v = allocate0(); - for (unsigned bit = num_tbits(); bit > 0;) { - --bit; + for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { if (val & (1ULL << bit)) { set(*v, bit, BIT_1); } else { From 6f7f957a266d8a22f628aaee29303ac650529f73 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:38:02 +0100 Subject: [PATCH 44/67] likely fix for #1287 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8938fb1b5..41f3f0e06 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -140,7 +140,7 @@ namespace z3 { class context { bool m_enable_exceptions; Z3_context m_ctx; - static void error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } + static void __cdecl error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; From c72b3356c16778fe21223f374f7679c1c0664e65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:41:02 +0100 Subject: [PATCH 45/67] fix #1286 Signed-off-by: Nikolaj Bjorner --- src/interp/iz3mgr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h index 6ca8fae34..e4c294059 100755 --- a/src/interp/iz3mgr.h +++ b/src/interp/iz3mgr.h @@ -96,7 +96,7 @@ class ast_r : public ast_i { ast_r(const ast_r &other) : ast_i(other) { _m = other._m; - _m->inc_ref(_ast); + if (_m) _m->inc_ref(_ast); } ast_r &operator=(const ast_r &other) { @@ -104,7 +104,7 @@ class ast_r : public ast_i { _m->dec_ref(_ast); _ast = other._ast; _m = other._m; - _m->inc_ref(_ast); + if (_m) _m->inc_ref(_ast); return *this; } From 52217f0600aaa2b2961f971d8648b8e3c7bf4f2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:56:05 +0100 Subject: [PATCH 46/67] fix #1290 Signed-off-by: Nikolaj Bjorner --- src/model/model_core.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index f94558097..4290700d4 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -86,18 +86,18 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); m_interp.remove(d); m_const_decls.erase(d); + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); return; } decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); m_finterp.remove(d); m_func_decls.erase(d); + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); } } From 1371caace28097b8d86ba4cd47be22492d419784 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 11:05:57 +0100 Subject: [PATCH 47/67] fix #1287, again Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 41f3f0e06..2200874d3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -140,7 +140,7 @@ namespace z3 { class context { bool m_enable_exceptions; Z3_context m_ctx; - static void __cdecl error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } + static void Z3_API error_handler(Z3_context /*c*/, Z3_error_code /*e*/) { /* do nothing */ } void init(config & c) { m_ctx = Z3_mk_context_rc(c); m_enable_exceptions = true; From 22fa108ffd91834eb5b4a98a3e14434750b7b8f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 11:07:22 +0100 Subject: [PATCH 48/67] fix #1288, again Signed-off-by: Nikolaj Bjorner --- src/muz/rel/tbv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 69cc4819a..5ef15303e 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -74,7 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { } tbv* tbv_manager::allocate(uint64 val) { tbv* v = allocate0(); - for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { + for (unsigned bit = std::min(63u, num_tbits()); bit-- > 0;) { if (val & (1ULL << bit)) { set(*v, bit, BIT_1); } else { From 06d75a616f6246eaa717ca34bb2719726d6858d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 11:40:17 +0100 Subject: [PATCH 49/67] fix #1288, again Signed-off-by: Nikolaj Bjorner --- src/muz/rel/tbv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/rel/tbv.cpp b/src/muz/rel/tbv.cpp index 5ef15303e..69cc4819a 100644 --- a/src/muz/rel/tbv.cpp +++ b/src/muz/rel/tbv.cpp @@ -74,7 +74,7 @@ tbv* tbv_manager::allocate(tbv const& bv) { } tbv* tbv_manager::allocate(uint64 val) { tbv* v = allocate0(); - for (unsigned bit = std::min(63u, num_tbits()); bit-- > 0;) { + for (unsigned bit = std::min(64u, num_tbits()); bit-- > 0;) { if (val & (1ULL << bit)) { set(*v, bit, BIT_1); } else { From d2ec927844120a4c26236e80b9bd8ae302de51f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 12:34:08 +0100 Subject: [PATCH 50/67] fix build break Signed-off-by: Nikolaj Bjorner --- src/model/model_core.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 4290700d4..833c254c3 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -86,18 +86,22 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { + auto k = ec->get_data().m_key; + auto v = ec->get_data().m_value; m_interp.remove(d); m_const_decls.erase(d); - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); + m_manager.dec_ref(k); + m_manager.dec_ref(v); return; } decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { + auto k = ef->get_data().m_key; + auto v = ef->get_data().m_value; m_finterp.remove(d); m_func_decls.erase(d); - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); + m_manager.dec_ref(k); + dealloc(v); } } From 356835533a8df3f6c995da2ac2b96c8d5079ed77 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 10:47:15 -0700 Subject: [PATCH 51/67] clean up debug output Signed-off-by: Nikolaj Bjorner --- src/model/model_core.cpp | 8 ++++---- src/sat/ba_solver.cpp | 40 +++++++++++++++++----------------------- src/smt/theory_pb.cpp | 1 - 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index f94558097..4290700d4 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -86,18 +86,18 @@ void model_core::register_decl(func_decl * d, func_interp * fi) { void model_core::unregister_decl(func_decl * d) { decl2expr::obj_map_entry * ec = m_interp.find_core(d); if (ec && ec->get_data().m_value != 0) { - m_manager.dec_ref(ec->get_data().m_key); - m_manager.dec_ref(ec->get_data().m_value); m_interp.remove(d); m_const_decls.erase(d); + m_manager.dec_ref(ec->get_data().m_key); + m_manager.dec_ref(ec->get_data().m_value); return; } decl2finterp::obj_map_entry * ef = m_finterp.find_core(d); if (ef && ef->get_data().m_value != 0) { - m_manager.dec_ref(ef->get_data().m_key); - dealloc(ef->get_data().m_value); m_finterp.remove(d); m_func_decls.erase(d); + m_manager.dec_ref(ef->get_data().m_key); + dealloc(ef->get_data().m_value); } } diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 0de5af885..668044e66 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -381,7 +381,7 @@ namespace sat { } else if (slack + true_val < p.k()) { if (p.lit() != null_literal) { - display(std::cout << "assign false literal ", p, true); + IF_VERBOSE(10, display(verbose_stream() << "assign false literal ", p, true);); s().assign(~p.lit(), justification()); } else { @@ -392,7 +392,6 @@ namespace sat { } else if (slack + true_val == p.k()) { literal_vector lits(p.literals()); - display(std::cout << "replace", p, true); assert_unconstrained(p.lit(), lits); remove_constraint(p, "is tight"); } @@ -1075,7 +1074,6 @@ namespace sat { int64 new_bound = m_bound; new_bound += i; if (new_bound < 0) { - // std::cout << "new negative bound " << new_bound << "\n"; m_overflow = true; } else if (new_bound > UINT_MAX) { @@ -1547,7 +1545,6 @@ namespace sat { } void ba_solver::add_constraint(constraint* c) { - // display(std::cout << "add " << c->learned() << " " << c->id() << "\n", *c, true); literal_vector lits(c->literals()); if (c->learned()) { m_learned.push_back(c); @@ -3093,7 +3090,6 @@ namespace sat { remove_constraint(c2, "subsumed"); ++m_stats.m_num_pb_subsumes; c1.set_learned(false); - std::cout << c1 << " subsumes " << c2 << "\n"; } else { TRACE("ba", tout << "self subsume cardinality\n";); @@ -3130,7 +3126,6 @@ namespace sat { removed_clauses.push_back(&c2); ++m_stats.m_num_clause_subsumes; c1.set_learned(false); - std::cout << c1 << " subsumes " << c2 << "\n"; } else { IF_VERBOSE(0, verbose_stream() << "self-subsume clause is TBD\n";); @@ -3157,7 +3152,6 @@ namespace sat { // IF_VERBOSE(10, verbose_stream() << c1 << " subsumes (" << lit << " " << w.get_literal() << ")\n";); if (!w.is_binary_non_learned_clause()) { c1.set_learned(false); - std::cout << c1 << " subsumes " << lit << " " << w.get_literal() << "\n"; } } else { @@ -3216,7 +3210,6 @@ namespace sat { \brief lit <=> conjunction of unconstrained lits */ void ba_solver::assert_unconstrained(literal lit, literal_vector const& lits) { - std::cout << "assert unconstrained\n"; if (lit == null_literal) { for (literal l : lits) { if (value(l) == l_undef) { @@ -3519,14 +3512,15 @@ namespace sat { // all elements of r are true, for (literal l : r) { if (value(l) != l_true) { - std::cout << "value of " << l << " is " << value(l) << "\n"; - display(std::cout, p, true); + IF_VERBOSE(0, verbose_stream() << "value of " << l << " is " << value(l) << "\n"; + display(verbose_stream(), p, true);); return false; } if (value(alit) == l_true && lvl(l) > lvl(alit)) { - std::cout << "level of premise " << l << " is " << lvl(l) << "\n"; - std::cout << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; - display(std::cout, p, true); + IF_VERBOSE(0, + verbose_stream() << "level of premise " << l << " is " << lvl(l) << "\n"; + verbose_stream() << "level of asserting literal " << alit << " is " << lvl(alit) << "\n"; + display(verbose_stream(), p, true);); return false; } // if (value(alit) == l_true && lvl(l) == lvl(alit)) { @@ -3547,14 +3541,15 @@ namespace sat { } } if (sum >= p.k()) { - std::cout << "sum is " << sum << " >= " << p.k() << "\n"; - display(std::cout, p, true); - std::cout << "id: " << p.id() << "\n"; - sum = 0; - for (wliteral wl : p) sum += wl.first; - std::cout << "overall sum " << sum << "\n"; - std::cout << "asserting literal: " << alit << "\n"; - std::cout << "reason: " << r << "\n"; + IF_VERBOSE(0, + verbose_stream() << "sum is " << sum << " >= " << p.k() << "\n"; + display(verbose_stream(), p, true); + verbose_stream() << "id: " << p.id() << "\n"; + sum = 0; + for (wliteral wl : p) sum += wl.first; + verbose_stream() << "overall sum " << sum << "\n"; + verbose_stream() << "asserting literal: " << alit << "\n"; + verbose_stream() << "reason: " << r << "\n";); return false; } for (wliteral wl : p) { @@ -3562,7 +3557,7 @@ namespace sat { return true; } } - std::cout << alit << " not found among literals\n"; + IF_VERBOSE(0, verbose_stream() << alit << " not found among literals\n";); return false; } @@ -3728,7 +3723,6 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { - std::cout << *c << "\n"; lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 12fddee13..92f66f4b6 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -474,7 +474,6 @@ namespace smt { if (pb.is_aux_bool(atom)) { bool_var abv = ctx.mk_bool_var(atom); ctx.set_var_theory(abv, get_id()); - std::cout << "aux bool " << ctx.get_scope_level() << " " << mk_pp(atom, get_manager()) << " " << literal(abv) << "\n"; return true; } From 10e4235b4c9495be46ca6c11786b445c94a668f8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 14:35:31 -0700 Subject: [PATCH 52/67] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 84 +++++++++++++++++++--------------------- src/sat/sat_elim_eqs.cpp | 56 +++++++++++++-------------- src/sat/sat_elim_eqs.h | 1 + src/sat/sat_solver.cpp | 3 ++ 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 668044e66..6f3d0da2f 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -363,8 +363,8 @@ namespace sat { } if (p.k() == 1 && p.lit() == null_literal) { literal_vector lits(p.literals()); - IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + IF_VERBOSE(10, display(verbose_stream() << "add clause: " << lits << "\n", p, true);); remove_constraint(p, "implies clause"); } else if (true_val == 0 && num_false == 0) { @@ -415,8 +415,8 @@ namespace sat { p.set_k(p.k() - true_val); if (p.k() == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); - s().mk_clause(lits.size(), lits.c_ptr(), p.learned()); + literal_vector lits(sz, p.literals().c_ptr()); + s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p, "is clause"); return; } @@ -501,7 +501,7 @@ namespace sat { // watch a prefix of literals, such that the slack of these is >= k bool ba_solver::init_watch(pb& p, bool is_true) { - clear_watch(p); + clear_watch(p); if (p.lit() != null_literal && p.lit().sign() == is_true) { p.negate(); } @@ -756,14 +756,13 @@ namespace sat { unsigned k = p.k(); unsigned sz = p.size(); bool all_units = true; + unsigned j = 0; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = p[i].second; unsigned w1 = m_weights[l.index()]; unsigned w2 = m_weights[(~l).index()]; if (w1 == 0 || w1 < w2) { - p.swap(i, sz - 1); - --sz; - --i; + continue; } else if (k <= w2) { k = 0; @@ -776,16 +775,16 @@ namespace sat { m_weights[l.index()] = 0; m_weights[(~l).index()] = 0; if (w1 == 0) { - p.swap(i, sz - 1); - --sz; - --i; + continue; } else { - p[i] = wliteral(w1, l); + p[j] = wliteral(w1, l); all_units &= w1 == 1; + ++j; } } } + sz = j; // clear weights for (wliteral wl : p) { m_weights[wl.second.index()] = 0; @@ -800,27 +799,28 @@ namespace sat { return; } - if (k == 1 && p.lit() == null_literal) { - literal_vector lits(p.literals()); + else if (k == 1 && p.lit() == null_literal) { + literal_vector lits(sz, p.literals().c_ptr()); s().mk_clause(sz, lits.c_ptr(), p.learned()); remove_constraint(p, "recompiled to clause"); return; } - if (all_units) { + else if (all_units) { literal_vector lits(sz, p.literals().c_ptr()); add_at_least(p.lit(), lits, k, p.learned()); remove_constraint(p, "recompiled to cardinality"); return; } - p.set_size(sz); - p.set_k(k); - SASSERT(p.well_formed()); - - // this could become a cardinality constraint by now. - if (p.lit() == null_literal || value(p.lit()) == l_true) { - init_watch(p, true); + else { + p.set_size(sz); + p.set_k(k); + SASSERT(p.well_formed()); + + if (p.lit() == null_literal || value(p.lit()) == l_true) { + init_watch(p, true); + } } } @@ -1281,13 +1281,8 @@ namespace sat { if (!create_asserting_lemma()) { goto bail_out; } - active2card(); - if (m_overflow) { - goto bail_out; - } - DEBUG_CODE(VERIFY(validate_conflict(m_lemma, m_A));); TRACE("ba", tout << m_lemma << "\n";); @@ -1407,7 +1402,7 @@ namespace sat { IF_VERBOSE(10, verbose_stream() << "(sat.backjump :new-level " << m_conflict_lvl << " :old-level " << old_level << ")\n";); goto adjust_conflict_level; } - return true; + return !m_overflow; } /* @@ -2564,7 +2559,6 @@ namespace sat { if (m_roots.empty()) return; // validate(); - m_visited.resize(s().num_vars()*2, false); m_constraint_removed = false; for (unsigned sz = m_constraints.size(), i = 0; i < sz; ++i) @@ -2572,7 +2566,6 @@ namespace sat { for (unsigned sz = m_learned.size(), i = 0; i < sz; ++i) flush_roots(*m_learned[i]); cleanup_constraints(); - // validate(); } @@ -2596,6 +2589,7 @@ namespace sat { } void ba_solver::recompile(card& c) { + // pre-condition is that the literals, except c.lit(), in c are watched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); @@ -2606,14 +2600,14 @@ namespace sat { bool all_units = true; unsigned sz = c.size(); unsigned_vector coeffs; + literal_vector lits; + unsigned j = 0; for (unsigned i = 0; i < sz && 0 < k; ++i) { literal l = c[i]; unsigned w = m_weights[l.index()]; unsigned w2 = m_weights[(~l).index()]; if (w == 0 || w < w2) { - c.swap(i, sz - 1); - --sz; - --i; + continue; } else if (k <= w2) { k = 0; @@ -2626,36 +2620,37 @@ namespace sat { m_weights[(~l).index()] = 0; m_weights[l.index()] = 0; if (w == 0) { - c.swap(i, sz - 1); - --sz; - --i; + continue; } else { all_units &= (w == 1); coeffs.push_back(w); + c[j++] = l; } } } + sz = j; + // clear weights for (literal l : c) { m_weights[l.index()] = 0; m_weights[(~l).index()] = 0; } - if (k == 0) { + if (k == 0 && c.lit() == null_literal) { remove_constraint(c, "recompiled to true"); return; } - if (k == 1) { - literal_vector lits(c.size(), c.begin()); - s().mk_clause(lits.size(), lits.c_ptr(), c.learned()); + if (k == 1 && c.lit() == null_literal) { + literal_vector lits(sz, c.literals().c_ptr()); + s().mk_clause(sz, lits.c_ptr(), c.learned()); remove_constraint(c, "recompiled to clause"); return; } c.set_size(sz); - c.set_k(k); + c.set_k(k); if (!all_units) { TRACE("ba", tout << "replacing by pb: " << c << "\n";); @@ -2671,6 +2666,7 @@ namespace sat { if (c.lit() == null_literal || value(c.lit()) == l_true) { init_watch(c, true); } + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); SASSERT(c.well_formed()); } } @@ -2692,7 +2688,6 @@ namespace sat { found = m_root_vars[c.get_lit(i).var()]; } if (!found) return; - //std::cout << "reroot " << c << "\n"; clear_watch(c); // this could create duplicate literals @@ -2730,7 +2725,6 @@ namespace sat { found_root |= l.var() == root.var(); } - //std::cout << "reroot " << c << "\n"; if (found_root) { split_root(c); c.negate(); @@ -2837,8 +2831,9 @@ namespace sat { for (unsigned v = 0; v < s().num_vars(); ++v) { literal lit(v, false); if (s().is_external(v) && - m_cnstr_use_list[lit.index()].size() == 0 && - m_cnstr_use_list[(~lit).index()].size() == 0 && !s().is_assumption(v)) { + m_cnstr_use_list[lit.index()].empty() && + m_cnstr_use_list[(~lit).index()].empty() && + !s().is_assumption(v)) { s().set_non_external(v); ++ext; } @@ -3723,6 +3718,7 @@ namespace sat { constraint* c = add_at_least(null_literal, lits, k, true); if (c) { + // IF_VERBOSE(0, verbose_stream() << *c << "\n";); lits.reset(); for (wliteral wl : m_wlits) { if (value(wl.second) == l_false) lits.push_back(wl.second); diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 8666218c6..7580ebba5 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -101,12 +101,13 @@ namespace sat { c[i] = norm(roots, c[i]); } std::sort(c.begin(), c.end()); + for (literal l : c) VERIFY(l == norm(roots, l)); TRACE("sats", tout << "after normalization/sorting: " << c << "\n"; tout.flush();); DEBUG_CODE({ - for (unsigned i = 0; i < sz; i++) { - CTRACE("sats", c[i] != norm(roots, c[i]), tout << c[i] << " " << norm(roots, c[i]) << "\n"; tout.flush();); - SASSERT(c[i] == norm(roots, c[i])); - } }); + for (literal l : c) { + CTRACE("sat", l != norm(roots, l), tout << l << " " << norm(roots, l) << "\n"; tout.flush();); + SASSERT(l == norm(roots, l)); + } }); // remove duplicates, and check if it is a tautology literal l_prev = null_literal; unsigned j = 0; @@ -122,13 +123,11 @@ namespace sat { break; // clause was satisfied if (val == l_false) continue; // skip - if (i != j) { - std::swap(c[i], c[j]); - } + c[j] = l; j++; } if (i < sz) { - // clause is a tautology or was simplified + // clause is a tautology or was simplified to true m_solver.del_clause(c); continue; } @@ -164,10 +163,7 @@ namespace sat { else c.update_approx(); - DEBUG_CODE({ - for (unsigned i = 0; i < j; i++) { - SASSERT(c[i] == norm(roots, c[i])); - } }); + DEBUG_CODE(for (literal l : c) VERIFY(l == norm(roots, l));); *it2 = *it; it2++; @@ -187,7 +183,6 @@ namespace sat { literal r = roots[v]; SASSERT(v != r.var()); if (m_solver.is_external(v) && !m_solver.set_root(l, r)) { - std::cout << "skip: " << l << " == " << r << "\n"; // cannot really eliminate v, since we have to notify extension of future assignments m_solver.mk_bin_clause(~l, r, false); m_solver.mk_bin_clause(l, ~r, false); @@ -199,29 +194,33 @@ namespace sat { mc.insert(e, ~l, r); mc.insert(e, l, ~r); } - m_solver.flush_roots(); } + m_solver.flush_roots(); } - bool elim_eqs::check_clauses(literal_vector const & roots) const { - clause_vector * vs[2] = { &m_solver.m_clauses, &m_solver.m_learned }; - for (unsigned i = 0; i < 2; i++) { - clause_vector & cs = *(vs[i]); - clause_vector::iterator it = cs.begin(); - clause_vector::iterator end = cs.end(); - for (; it != end; ++it) { - clause & c = *(*it); - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - CTRACE("elim_eqs_bug", m_solver.was_eliminated(c[i].var()), tout << "lit: " << c[i] << " " << norm(roots, c[i]) << "\n"; - tout << c << "\n";); - SASSERT(!m_solver.was_eliminated(c[i].var())); - } + bool elim_eqs::check_clause(clause const& c, literal_vector const& roots) const { + for (literal l : c) { + CTRACE("elim_eqs_bug", m_solver.was_eliminated(l.var()), tout << "lit: " << l << " " << norm(roots, l) << "\n"; + tout << c << "\n";); + if (m_solver.was_eliminated(l.var())) { + IF_VERBOSE(0, verbose_stream() << c << " contains eliminated literal " << l << " " << norm(roots, l) << "\n";); + UNREACHABLE(); } } return true; } + + bool elim_eqs::check_clauses(literal_vector const & roots) const { + for (clause * cp : m_solver.m_clauses) + if (!check_clause(*cp, roots)) + return false; + for (clause * cp : m_solver.m_learned) + if (!check_clause(*cp, roots)) + return false; + return true; + } + void elim_eqs::operator()(literal_vector const & roots, bool_var_vector const & to_elim) { cleanup_bin_watches(roots); TRACE("elim_eqs", tout << "after bin cleanup\n"; m_solver.display(tout);); @@ -230,6 +229,7 @@ namespace sat { cleanup_clauses(roots, m_solver.m_learned); if (m_solver.inconsistent()) return; save_elim(roots, to_elim); + VERIFY(check_clauses(roots)); m_solver.propagate(false); SASSERT(check_clauses(roots)); } diff --git a/src/sat/sat_elim_eqs.h b/src/sat/sat_elim_eqs.h index 0422b60df..15c50097d 100644 --- a/src/sat/sat_elim_eqs.h +++ b/src/sat/sat_elim_eqs.h @@ -30,6 +30,7 @@ namespace sat { void cleanup_clauses(literal_vector const & roots, clause_vector & cs); void cleanup_bin_watches(literal_vector const & roots); bool check_clauses(literal_vector const & roots) const; + bool check_clause(clause const& c, literal_vector const& roots) const; public: elim_eqs(solver & s); void operator()(literal_vector const & roots, bool_var_vector const & to_elim); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index cc79e75ff..8011837dd 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -372,6 +372,9 @@ namespace sat { clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; + for (unsigned i = 0; i + 1 < num_lits; ++i) { + VERIFY (lits[i] != ~lits[i + 1]); + } clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); From f359f238851d8c1a5db11a95d4ded3639813db9a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 15:47:06 -0700 Subject: [PATCH 53/67] another fix for #1288 Signed-off-by: Nikolaj Bjorner --- src/util/mpz.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 9569ac280..7cf87b24b 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -558,14 +558,13 @@ void mpz_manager::big_rem(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { - if (is_small(a) && is_small(b)) { + COMPILE_TIME_ASSERT(sizeof(a.m_val) == sizeof(int)); + if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) { int _a = a.m_val; int _b = b.m_val; if (_a < 0) _a = -_a; if (_b < 0) _b = -_b; unsigned r = u_gcd(_a, _b); - // Remark: r is (INT_MAX + 1) - // If a == b == INT_MIN set(c, r); } else { From f85c02600f19d6c5e7a7a67aaa2d53a8002ce71a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2017 16:07:58 -0700 Subject: [PATCH 54/67] remove verificaiton code Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 1 - src/sat/sat_elim_eqs.cpp | 1 - src/sat/sat_solver.cpp | 3 --- 3 files changed, 5 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6f3d0da2f..f1f32eef5 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1387,7 +1387,6 @@ namespace sat { IF_VERBOSE(20, verbose_stream() << "(sat.card slack: " << slack << " skipped: " << num_skipped << ")\n";); return false; } - if (m_lemma[0] == null_literal) { if (m_lemma.size() == 1) { diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 7580ebba5..d10bea7bb 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -229,7 +229,6 @@ namespace sat { cleanup_clauses(roots, m_solver.m_learned); if (m_solver.inconsistent()) return; save_elim(roots, to_elim); - VERIFY(check_clauses(roots)); m_solver.propagate(false); SASSERT(check_clauses(roots)); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 8011837dd..cc79e75ff 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -372,9 +372,6 @@ namespace sat { clause * solver::mk_nary_clause(unsigned num_lits, literal * lits, bool learned) { m_stats.m_mk_clause++; - for (unsigned i = 0; i + 1 < num_lits; ++i) { - VERIFY (lits[i] != ~lits[i + 1]); - } clause * r = m_cls_allocator.mk_clause(num_lits, lits, learned); SASSERT(!learned || r->is_learned()); bool reinit = attach_nary_clause(*r); From 79b2a4f605cf1acd7dd8608a1df09b4ab2a359cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 07:22:02 -0700 Subject: [PATCH 55/67] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 57 ++++++++++++++++++++++++------------- src/util/memory_manager.cpp | 3 +- src/util/vector.h | 1 + 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index f1f32eef5..1dbaefbce 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -218,11 +218,16 @@ namespace sat { bool ba_solver::init_watch(card& c, bool is_true) { clear_watch(c); - if (c.lit() != null_literal && c.lit().sign() == is_true) { + literal root = c.lit(); + if (root != null_literal && root.sign() == is_true) { c.negate(); } + if (root != null_literal) { + if (!is_watched(root, c)) watch_literal(root, c); + if (!is_watched(~root, c)) watch_literal(~root, c); + } TRACE("ba", display(tout << "init watch: ", c, true);); - SASSERT(c.lit() == null_literal || value(c.lit()) == l_true); + SASSERT(root == null_literal || value(root) == l_true); unsigned j = 0, sz = c.size(), bound = c.k(); // put the non-false literals into the head. @@ -554,8 +559,7 @@ namespace sat { p.set_slack(slack); p.set_num_watch(num_watch); - VERIFY(validate_watch(p, null_literal)); - // SASSERT(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); TRACE("ba", display(tout << "init watch: ", p, true);); @@ -644,7 +648,7 @@ namespace sat { return l_undef; } - VERIFY(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); // SASSERT(validate_watch(p, null_literal)); SASSERT(index < num_watch); @@ -680,7 +684,7 @@ namespace sat { slack += val; p.set_slack(slack); p.set_num_watch(num_watch); - VERIFY(validate_watch(p, null_literal)); + SASSERT(validate_watch(p, null_literal)); BADLOG(display(verbose_stream() << "conflict: " << alit << " watch: " << p.num_watch() << " size: " << p.size(), p, true)); SASSERT(bound <= slack); TRACE("ba", tout << "conflict " << alit << "\n";); @@ -721,7 +725,7 @@ namespace sat { } } - VERIFY(validate_watch(p, alit)); // except that alit is still watched. + SASSERT(validate_watch(p, alit)); // except that alit is still watched. TRACE("ba", display(tout << "assign: " << alit << "\n", p, true);); @@ -739,11 +743,8 @@ namespace sat { unwatch_literal(p[i].second, p); } p.set_num_watch(0); - // debug code: - DEBUG_CODE( - for (wliteral wl : p) { - VERIFY(!is_watched(wl.second, p)); - }); + + DEBUG_CODE(for (wliteral wl : p) VERIFY(!is_watched(wl.second, p));); } void ba_solver::recompile(pb& p) { @@ -1558,10 +1559,14 @@ namespace sat { } else { s().set_external(lit.var()); - get_wlist(lit).push_back(watched(c->index())); - get_wlist(~lit).push_back(watched(c->index())); + watch_literal(lit, *c); + watch_literal(~lit, *c); } SASSERT(c->well_formed()); + if (c->id() == 1344) { + std::cout << "is watched: " << lit << " " << is_watched(lit, *c) << "\n"; + std::cout << "is watched: " << ~lit << " " << is_watched(~lit, *c) << "\n"; + } } @@ -1982,10 +1987,17 @@ namespace sat { } void ba_solver::unwatch_literal(literal lit, constraint& c) { + if (c.index() == 1344) { + std::cout << "unwatch: " << lit << "\n"; + } get_wlist(~lit).erase(watched(c.index())); } void ba_solver::watch_literal(literal lit, constraint& c) { + if (c.index() == 1344) { + std::cout << "watch: " << lit << "\n"; + } + get_wlist(~lit).push_back(watched(c.index())); } @@ -2588,7 +2600,9 @@ namespace sat { } void ba_solver::recompile(card& c) { - // pre-condition is that the literals, except c.lit(), in c are watched. + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); + + // pre-condition is that the literals, except c.lit(), in c are unwatched. if (c.id() == _bad_id) std::cout << "recompile: " << c << "\n"; // IF_VERBOSE(0, verbose_stream() << "re: " << c << "\n";); m_weights.resize(2*s().num_vars(), 0); @@ -2682,6 +2696,11 @@ namespace sat { void ba_solver::flush_roots(constraint& c) { + if (c.lit() != null_literal && !is_watched(c.lit(), c)) { + watch_literal(c.lit(), c); + watch_literal(~c.lit(), c); + } + SASSERT(c.lit() == null_literal || is_watched(c.lit(), c)); bool found = c.lit() != null_literal && m_root_vars[c.lit().var()]; for (unsigned i = 0; !found && i < c.size(); ++i) { found = m_root_vars[c.get_lit(i).var()]; @@ -2696,12 +2715,12 @@ namespace sat { } literal root = c.lit(); - if (c.lit() != null_literal && m_roots[c.lit().index()] != c.lit()) { - root = m_roots[c.lit().index()]; + if (root != null_literal && m_roots[root.index()] != root) { + root = m_roots[root.index()]; nullify_tracking_literal(c); c.update_literal(root); - get_wlist(root).push_back(watched(c.index())); - get_wlist(~root).push_back(watched(c.index())); + watch_literal(root, c); + watch_literal(~root, c); } bool found_dup = false; diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 0b394b450..d2e25294d 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -58,9 +58,10 @@ static void throw_out_of_memory() { g_memory_out_of_memory = true; } + __assume(0); + if (g_exit_when_out_of_memory) { std::cerr << g_out_of_memory_msg << "\n"; - __assume(0); exit(ERR_MEMOUT); } else { diff --git a/src/util/vector.h b/src/util/vector.h index 2d499a900..2e2640de3 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -72,6 +72,7 @@ class vector { SZ new_capacity = (3 * old_capacity + 1) >> 1; SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { + UNREACHABLE(); throw default_exception("Overflow encountered when expanding vector"); } SZ *mem = (SZ*)memory::reallocate(reinterpret_cast(m_data)-2, new_capacity_T); From 42de2743076723171b91d9ec17cbd8468398a88a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 07:49:20 -0700 Subject: [PATCH 56/67] bug fixes Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 1dbaefbce..6a68c30c9 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -221,6 +221,7 @@ namespace sat { literal root = c.lit(); if (root != null_literal && root.sign() == is_true) { c.negate(); + root.neg(); } if (root != null_literal) { if (!is_watched(root, c)) watch_literal(root, c); @@ -1563,10 +1564,6 @@ namespace sat { watch_literal(~lit, *c); } SASSERT(c->well_formed()); - if (c->id() == 1344) { - std::cout << "is watched: " << lit << " " << is_watched(lit, *c) << "\n"; - std::cout << "is watched: " << ~lit << " " << is_watched(~lit, *c) << "\n"; - } } @@ -1987,17 +1984,10 @@ namespace sat { } void ba_solver::unwatch_literal(literal lit, constraint& c) { - if (c.index() == 1344) { - std::cout << "unwatch: " << lit << "\n"; - } get_wlist(~lit).erase(watched(c.index())); } void ba_solver::watch_literal(literal lit, constraint& c) { - if (c.index() == 1344) { - std::cout << "watch: " << lit << "\n"; - } - get_wlist(~lit).push_back(watched(c.index())); } From cae414e575299d976899b764041195ff36f484e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 13:59:44 -0700 Subject: [PATCH 57/67] fixes for #1296, removing COMPILE_TIME_ASSERT Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/maximize_ac_sharing.cpp | 5 +++-- src/sat/sat_watched.h | 8 ++++---- src/smt/smt_theory_var_list.h | 4 ++-- src/util/approx_set.h | 4 ++-- src/util/bit_vector.h | 2 +- src/util/debug.h | 1 - src/util/double_manager.h | 2 +- src/util/mpf.cpp | 6 +++--- src/util/mpff.cpp | 4 ++-- src/util/mpn.cpp | 2 +- src/util/mpz.cpp | 10 +++++----- src/util/uint_set.h | 1 - src/util/util.h | 6 +++--- 13 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/ast/rewriter/maximize_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp index d7e8df7a2..a838f59fa 100644 --- a/src/ast/rewriter/maximize_ac_sharing.cpp +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -54,13 +54,13 @@ br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";); try_to_reuse: if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) { - for (unsigned i = 0; i < num_args - 1; i++) { + for (unsigned i = 0; i + 1 < num_args; i++) { for (unsigned j = i + 1; j < num_args; j++) { if (contains(f, _args[i], _args[j])) { TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); _args[i] = m.mk_app(f, _args[i], _args[j]); SASSERT(num_args > 1); - for (unsigned w = j; w < num_args - 1; w++) { + for (unsigned w = j; w + 1 < num_args; w++) { _args[w] = _args[w+1]; } num_args--; @@ -144,6 +144,7 @@ void maximize_ac_sharing::restore_entries(unsigned old_lim) { while (i != old_lim) { --i; entry * e = m_entries[i]; + m_cache.remove(e); m.dec_ref(e->m_arg1); m.dec_ref(e->m_arg2); } diff --git a/src/sat/sat_watched.h b/src/sat/sat_watched.h index e5a02953b..639d3e6a8 100644 --- a/src/sat/sat_watched.h +++ b/src/sat/sat_watched.h @@ -109,10 +109,10 @@ namespace sat { bool operator!=(watched const & w) const { return !operator==(w); } }; - COMPILE_TIME_ASSERT(0 <= watched::BINARY && watched::BINARY <= 3); - COMPILE_TIME_ASSERT(0 <= watched::TERNARY && watched::TERNARY <= 3); - COMPILE_TIME_ASSERT(0 <= watched::CLAUSE && watched::CLAUSE <= 3); - COMPILE_TIME_ASSERT(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3); + static_assert(0 <= watched::BINARY && watched::BINARY <= 3, ""); + static_assert(0 <= watched::TERNARY && watched::TERNARY <= 3, ""); + static_assert(0 <= watched::CLAUSE && watched::CLAUSE <= 3, ""); + static_assert(0 <= watched::EXT_CONSTRAINT && watched::EXT_CONSTRAINT <= 3, ""); struct watched_lt { bool operator()(watched const & w1, watched const & w2) const { diff --git a/src/smt/smt_theory_var_list.h b/src/smt/smt_theory_var_list.h index d7e246824..aa2816786 100644 --- a/src/smt/smt_theory_var_list.h +++ b/src/smt/smt_theory_var_list.h @@ -67,9 +67,9 @@ namespace smt { }; // 32 bit machine - COMPILE_TIME_ASSERT(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int)); + static_assert(sizeof(expr*) != 4 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int), "32 bit"); // 64 bit machine - COMPILE_TIME_ASSERT(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int)); + static_assert(sizeof(expr*) != 8 || sizeof(theory_var_list) == sizeof(theory_var_list *) + sizeof(int) + /* a structure must be aligned */ sizeof(int), "64 bit"); }; #endif /* SMT_THEORY_VAR_LIST_H_ */ diff --git a/src/util/approx_set.h b/src/util/approx_set.h index e696d52ee..1cb7ae9f2 100644 --- a/src/util/approx_set.h +++ b/src/util/approx_set.h @@ -29,7 +29,7 @@ public: static const unsigned long long zero = 0ull; static const unsigned long long one = 1ull; }; -COMPILE_TIME_ASSERT(sizeof(unsigned long long) == 8); +static_assert(sizeof(unsigned long long) == 8, ""); template <> class approx_set_traits { public: @@ -37,7 +37,7 @@ public: static const unsigned zero = 0; static const unsigned one = 1; }; -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); template class approx_set_tpl : private T2U_Proc { diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 6a254e399..2d42e35a2 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -24,7 +24,7 @@ Revision History: #include "util/vector.h" #include "util/memory_manager.h" -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 4 bytes"); #define BV_DEFAULT_CAPACITY 2 class bit_vector { diff --git a/src/util/debug.h b/src/util/debug.h index e0ceb9a64..536df4588 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -90,7 +90,6 @@ bool is_debug_enabled(const char * tag); exit(-1); \ } -#define COMPILE_TIME_ASSERT(expr) static_assert(expr, "") void finalize_debug(); /* diff --git a/src/util/double_manager.h b/src/util/double_manager.h index 33cccf2af..7532a3b8b 100644 --- a/src/util/double_manager.h +++ b/src/util/double_manager.h @@ -97,7 +97,7 @@ public: } }; -COMPILE_TIME_ASSERT(sizeof(uint64) == sizeof(double)); +static_assert(sizeof(uint64) == sizeof(double), ""); #endif /* DOUBLE_MANAGER_H_ */ diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 5e7233110..3218419a9 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -73,7 +73,7 @@ mpf_manager::~mpf_manager() { } void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { - COMPILE_TIME_ASSERT(sizeof(int) == 4); + static_assert(sizeof(int) == 4, "assume integers are 4 bytes"); o.sign = false; o.ebits = ebits; @@ -119,7 +119,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { // double === mpf(11, 53) - COMPILE_TIME_ASSERT(sizeof(double) == 8); + static_assert(sizeof(double) == 8, "doubles are 8 bytes"); uint64 raw; memcpy(&raw, &value, sizeof(double)); @@ -155,7 +155,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, float value) { // single === mpf(8, 24) - COMPILE_TIME_ASSERT(sizeof(float) == 4); + static_assert(sizeof(float) == 4, "floats are 4 bytes"); unsigned int raw; memcpy(&raw, &value, sizeof(float)); diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index 459b0691c..eac9cc80c 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -27,8 +27,8 @@ Revision History: #include "util/bit_util.h" #include "util/trace.h" -COMPILE_TIME_ASSERT(sizeof(mpn_digit) == sizeof(unsigned)); -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(mpn_digit) == sizeof(unsigned), ""); +static_assert(sizeof(unsigned) == 4, "unsigned haven't changed size for a while"); // MIN_MSW is an shorthand for 0x8000..00, i.e., the minimal most significand word. #define MIN_MSW (1u << (sizeof(unsigned) * 8 - 1)) diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index 65223133f..2059ea6fd 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -24,7 +24,7 @@ Revision History: #define max(a,b) (((a) > (b)) ? (a) : (b)) typedef uint64 mpn_double_digit; -COMPILE_TIME_ASSERT(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit)); +static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment"); const mpn_digit mpn_manager::zero = 0; diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 7cf87b24b..7ad472ef1 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -558,7 +558,7 @@ void mpz_manager::big_rem(mpz const & a, mpz const & b, mpz & c) { template void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { - COMPILE_TIME_ASSERT(sizeof(a.m_val) == sizeof(int)); + static_assert(sizeof(a.m_val) == sizeof(int), "size mismatch"); if (is_small(a) && is_small(b) && a.m_val != INT_MIN && b.m_val != INT_MIN) { int _a = a.m_val; int _b = b.m_val; @@ -724,7 +724,7 @@ void mpz_manager::gcd(mpz const & a, mpz const & b, mpz & c) { #ifdef LEHMER_GCD // For now, it only works if sizeof(digit_t) == sizeof(unsigned) - COMPILE_TIME_ASSERT(sizeof(digit_t) == sizeof(unsigned)); + static_assert(sizeof(digit_t) == sizeof(unsigned), ""); int64 a_hat, b_hat, A, B, C, D, T, q, a_sz, b_sz; mpz a1, b1, t, r, tmp; @@ -1754,7 +1754,7 @@ void mpz_manager::mul2k(mpz & a, unsigned k) { } #ifndef _MP_GMP -COMPILE_TIME_ASSERT(sizeof(digit_t) == 4 || sizeof(digit_t) == 8); +static_assert(sizeof(digit_t) == 4 || sizeof(digit_t) == 8, ""); #endif template @@ -1821,7 +1821,7 @@ unsigned mpz_manager::log2(mpz const & a) { if (is_small(a)) return ::log2((unsigned)a.m_val); #ifndef _MP_GMP - COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); + static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; @@ -1843,7 +1843,7 @@ unsigned mpz_manager::mlog2(mpz const & a) { if (is_small(a)) return ::log2((unsigned)-a.m_val); #ifndef _MP_GMP - COMPILE_TIME_ASSERT(sizeof(digit_t) == 8 || sizeof(digit_t) == 4); + static_assert(sizeof(digit_t) == 8 || sizeof(digit_t) == 4, ""); mpz_cell * c = a.m_ptr; unsigned sz = c->m_size; digit_t * ds = c->m_digits; diff --git a/src/util/uint_set.h b/src/util/uint_set.h index 33c39eeb2..352189ef1 100644 --- a/src/util/uint_set.h +++ b/src/util/uint_set.h @@ -22,7 +22,6 @@ Revision History: #include "util/util.h" #include "util/vector.h" -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); class uint_set : unsigned_vector { diff --git a/src/util/util.h b/src/util/util.h index 23c2c1657..1f753099c 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -33,13 +33,13 @@ Revision History: typedef unsigned long long uint64; #endif -COMPILE_TIME_ASSERT(sizeof(uint64) == 8); +static_assert(sizeof(uint64) == 8, "64 bits please"); #ifndef int64 typedef long long int64; #endif -COMPILE_TIME_ASSERT(sizeof(int64) == 8); +static_assert(sizeof(int64) == 8, "64 bits"); #ifndef INT64_MIN #define INT64_MIN static_cast(0x8000000000000000ull) @@ -111,7 +111,7 @@ inline unsigned next_power_of_two(unsigned v) { unsigned log2(unsigned v); unsigned uint64_log2(uint64 v); -COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); +static_assert(sizeof(unsigned) == 4, "unsigned are 32 bits"); // Return the number of 1 bits in v. static inline unsigned get_num_1bits(unsigned v) { From a0cd6e0fca14003795f5651002232645544a17cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Oct 2017 16:47:23 -0700 Subject: [PATCH 58/67] adding outline for parallel tactic Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 4 +- src/sat/sat_lookahead.cpp | 2 + src/tactic/portfolio/CMakeLists.txt | 6 ++- src/tactic/portfolio/parallel_tactic.cpp | 48 +++++++++++++++++++++++ src/tactic/portfolio/parallel_tactic.h | 27 +++++++++++++ src/tactic/portfolio/solver2lookahead.cpp | 24 ++++++++++++ src/tactic/portfolio/solver2lookahead.h | 26 ++++++++++++ 7 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 src/tactic/portfolio/parallel_tactic.cpp create mode 100644 src/tactic/portfolio/parallel_tactic.h create mode 100644 src/tactic/portfolio/solver2lookahead.cpp create mode 100644 src/tactic/portfolio/solver2lookahead.h diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index d10bea7bb..424de0e7c 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -96,9 +96,9 @@ namespace sat { if (!c.frozen()) m_solver.detach_clause(c); // apply substitution - for (i = 0; i < sz; i++) { - SASSERT(!m_solver.was_eliminated(c[i].var())); + for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); + SASSERT(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 596b9abe7..11fb7f008 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -1623,6 +1623,8 @@ namespace sat { } void lookahead::reset_lookahead_reward() { + SASSERT(m_search_mode == lookahead_mode::lookahead1 || + m_search_mode == lookahead_mode::lookahead2); m_qhead = m_qhead_lim.back(); TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 570db8f6a..c4ae795c6 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -1,11 +1,13 @@ z3_add_component(portfolio SOURCES + bounded_int2bv_solver.cpp default_tactic.cpp enum2bv_solver.cpp - pb2bv_solver.cpp - bounded_int2bv_solver.cpp fd_solver.cpp + parallel_tactic.cpp + pb2bv_solver.cpp smt_strategic_solver.cpp + solver2lookahead.cpp COMPONENT_DEPENDENCIES aig_tactic fp diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp new file mode 100644 index 000000000..497587cd3 --- /dev/null +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -0,0 +1,48 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + parallel_solver.cpp + +Abstract: + + Parallel solver in the style of Treengeling. + + It assumes a solver that supports good lookaheads. + + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ + +#include "solver/solver.h" +#include "tactic/tactic.h" + +class parallel_tactic : public tactic { + ref m_solver; +public: + parallel_tactic(solver* s) : m_solver(s) {} + + void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { + NOT_IMPLEMENTED_YET(); + } + + void cleanup() { + NOT_IMPLEMENTED_YET(); + } + + tactic* translate(ast_manager& m) { + NOT_IMPLEMENTED_YET(); + return 0; + } +}; + +tactic * mk_parallel_tactic(solver* s) { + return alloc(parallel_tactic, s); +} + diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h new file mode 100644 index 000000000..a84c7be4d --- /dev/null +++ b/src/tactic/portfolio/parallel_tactic.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + parallel_tactic.h + +Abstract: + + Parallel tactic in the style of Treengeling. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#ifndef PARALLEL_TACTIC_H_ +#define PARALLEL_TACTIC_H_ + +class solver; +class tactic; + +tactic * mk_parallel_tactic(solver* s); + +#endif diff --git a/src/tactic/portfolio/solver2lookahead.cpp b/src/tactic/portfolio/solver2lookahead.cpp new file mode 100644 index 000000000..0c18ab079 --- /dev/null +++ b/src/tactic/portfolio/solver2lookahead.cpp @@ -0,0 +1,24 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver2lookahead.cpp + +Abstract: + + Lookahead wrapper for arbitrary solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#include "sat/sat_solver/inc_sat_solver.h" +#include "solver/solver.h" + +solver * mk_solver2lookahead(solver* s) { + return 0; +} diff --git a/src/tactic/portfolio/solver2lookahead.h b/src/tactic/portfolio/solver2lookahead.h new file mode 100644 index 000000000..80d73ddf3 --- /dev/null +++ b/src/tactic/portfolio/solver2lookahead.h @@ -0,0 +1,26 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + solver2lookahead.h + +Abstract: + + Lookahead wrapper for arbitrary solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2017-10-9 + +Notes: + +--*/ +#ifndef SOLVER2LOOKAHEAD_H_ +#define SOLVER2LOOKAHEAD_H_ + +class solver; + +solver * mk_solver2lookahead(solver* s); + +#endif From 7f693186a0c0ca9cc0d15ff3fd8fbc1734e95ee1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Oct 2017 07:10:04 -0700 Subject: [PATCH 59/67] trying to address leak reported in #1297 Signed-off-by: Nikolaj Bjorner --- src/api/api_parsers.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index bef31e9f1..7a68efbd8 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -69,6 +69,7 @@ extern "C" { ok = false; } mk_c(c)->m_smtlib_error_buffer = outs.str(); + outs.clear(); if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); @@ -98,6 +99,7 @@ extern "C" { ok = false; } mk_c(c)->m_smtlib_error_buffer = outs.str(); + outs.clear(); if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); From 8b32c15ac9483c26d3ae74023c9072c8629b0dd0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Oct 2017 11:49:31 -0700 Subject: [PATCH 60/67] use clause structure for nary Signed-off-by: Nikolaj Bjorner --- src/sat/sat_elim_eqs.cpp | 2 +- src/sat/sat_lookahead.cpp | 240 +++++++++++++++++++++-- src/sat/sat_lookahead.h | 53 ++++- src/tactic/portfolio/parallel_tactic.cpp | 178 ++++++++++++++++- 4 files changed, 455 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_elim_eqs.cpp b/src/sat/sat_elim_eqs.cpp index 424de0e7c..7eb307f85 100644 --- a/src/sat/sat_elim_eqs.cpp +++ b/src/sat/sat_elim_eqs.cpp @@ -98,7 +98,7 @@ namespace sat { // apply substitution for (i = 0; i < sz; i++) { c[i] = norm(roots, c[i]); - SASSERT(!m_solver.was_eliminated(c[i].var())); + VERIFY(!m_solver.was_eliminated(c[i].var())); } std::sort(c.begin(), c.end()); for (literal l : c) VERIFY(l == norm(roots, l)); diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 11fb7f008..7ce2b53b9 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -312,10 +312,11 @@ namespace sat { } bool lookahead::is_unsat() const { - bool all_false = true; - bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. +#if OLD_NARY + bool all_false = true; + bool first = true; for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -332,6 +333,15 @@ namespace sat { all_false &= is_false(l); } } +#else + for (nary* n : m_nary_clauses) { + bool all_false = true; + for (literal l : *n) { + all_false &= is_false(l); + } + if (all_false) return true; + } +#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -366,10 +376,11 @@ namespace sat { } } } - bool no_true = true; - bool first = true; // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. +#if OLD_NARY + bool no_true = true; + bool first = true; for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -385,6 +396,15 @@ namespace sat { no_true &= !is_true(l); } } +#else + for (nary * n : m_nary_clauses) { + bool no_true = true; + for (literal l : *n) { + no_true &= !is_true(l); + } + if (no_true) return false; + } +#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -457,6 +477,7 @@ namespace sat { sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; } sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; literal lit; @@ -470,6 +491,9 @@ namespace sat { unsigned len = m_nary_literals[idx]; sum += pow(0.5, len) * to_add / len; } +#else + +#endif return sum; } @@ -488,10 +512,17 @@ namespace sat { } sum += 0.25 * m_ternary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned cls_idx : m_nary[(~l).index()]) { if (sz-- == 0) break; sum += pow(0.5, m_nary_literals[cls_idx]); } +#else + for (nary * n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + sum += pow(0.5, n->size()); + } +#endif return sum; } @@ -866,8 +897,13 @@ namespace sat { m_ternary.push_back(svector()); m_ternary_count.push_back(0); m_ternary_count.push_back(0); +#if OLD_NARY m_nary.push_back(unsigned_vector()); m_nary.push_back(unsigned_vector()); +#else + m_nary.push_back(ptr_vector()); + m_nary.push_back(ptr_vector()); +#endif m_nary_count.push_back(0); m_nary_count.push_back(0); m_bstamp.push_back(0); @@ -1254,8 +1290,10 @@ namespace sat { // new n-ary clause managment void lookahead::add_clause(clause const& c) { + SASSERT(c.size() > 3); + +#if OLD_NARY unsigned sz = c.size(); - SASSERT(sz > 3); unsigned idx = m_nary_literals.size(); m_nary_literals.push_back(sz); for (literal l : c) { @@ -1264,7 +1302,15 @@ namespace sat { m_nary[l.index()].push_back(idx); SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); } - m_nary_literals.push_back(null_literal.index()); + m_nary_literals.push_back(null_literal.index()); +#else + void * mem = m_allocator.allocate(nary::get_obj_size(c.size())); + nary * n = new (mem) nary(c.size(), c.begin()); + m_nary_clauses.push_back(n); + for (literal l : c) { + m_nary[l.index()].push_back(n); + } +#endif } @@ -1274,6 +1320,7 @@ namespace sat { literal lit; SASSERT(m_search_mode == lookahead_mode::searching); +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = --m_nary_literals[idx]; @@ -1323,12 +1370,69 @@ namespace sat { } } } +#else + for (nary * n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + unsigned len = n->dec_size(); + if (m_inconsistent) continue; + if (len <= 1) continue; // already processed + // find the two unassigned literals, if any + if (len == 2) { + literal l1 = null_literal; + literal l2 = null_literal; + bool found_true = false; + for (literal lit : *n) { + if (!is_fixed(lit)) { + if (l1 == null_literal) { + l1 = lit; + } + else { + SASSERT(l2 == null_literal); + l2 = lit; + break; + } + } + else if (is_true(lit)) { + n->set_head(lit); + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + } + else if (l2 == null_literal) { + // clause may get revisited during propagation, when l2 is true in this clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); + // remove_clause_at(~l, idx); + propagated(l1); + } + else { + // extract binary clause. A unary or empty clause may get revisited, + // but we skip it then because it is already handled as a binary clause. + // m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause. + // remove_clause_at(~l, idx); + try_add_binary(l1, l2); + } + } + } +#endif // clauses where l is positive: sz = m_nary_count[l.index()]; +#if OLD_NARY for (unsigned idx : m_nary[l.index()]) { if (sz-- == 0) break; remove_clause_at(l, idx); } +#else + for (nary* n : m_nary[l.index()]) { + if (sz-- == 0) break; + remove_clause_at(l, *n); + } +#endif } void lookahead::propagate_clauses_lookahead(literal l) { @@ -1338,6 +1442,7 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; literal l1 = null_literal; @@ -1404,9 +1509,75 @@ namespace sat { } } } +#else + for (nary* n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + literal l1 = null_literal; + literal l2 = null_literal; + bool found_true = false; + unsigned nonfixed = 0; + for (literal lit : *n) { + if (!is_fixed(lit)) { + ++nonfixed; + if (l1 == null_literal) { + l1 = lit; + } + else if (l2 == null_literal) { + l2 = lit; + } + } + else if (is_true(lit)) { + found_true = true; + break; + } + } + if (found_true) { + // skip, the clause will be removed when propagating on 'lit' + } + else if (l1 == null_literal) { + set_conflict(); + return; + } + else if (l2 == null_literal) { + propagated(l1); + } + else if (m_search_mode == lookahead_mode::lookahead2) { + continue; + } + else { + SASSERT(nonfixed >= 2); + SASSERT(m_search_mode == lookahead_mode::lookahead1); + switch (m_config.m_reward_type) { + case heule_schur_reward: { + double to_add = 0; + for (literal lit : *n) { + if (!is_fixed(lit)) { + to_add += literal_occs(lit); + } + } + m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; + break; + } + case heule_unit_reward: + m_lookahead_reward += pow(0.5, nonfixed); + break; + case ternary_reward: + if (nonfixed == 2) { + m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; + } + else { + m_lookahead_reward += (double)0.001; + } + break; + case unit_literal_reward: + break; + } + } + } +#endif } - +#if OLD_NARY void lookahead::remove_clause_at(literal l, unsigned clause_idx) { unsigned j = clause_idx; literal lit; @@ -1429,21 +1600,50 @@ namespace sat { } UNREACHABLE(); } +#else + + void lookahead::remove_clause_at(literal l, nary& n) { + for (literal lit : n) { + if (lit != l) { + remove_clause(lit, n); + } + } + } + + void lookahead::remove_clause(literal l, nary& n) { + ptr_vector& pclauses = m_nary[l.index()]; + unsigned sz = m_nary_count[l.index()]--; + for (unsigned i = sz; i > 0; ) { + --i; + if (&n == pclauses[i]) { + std::swap(pclauses[i], pclauses[sz-1]); + return; + } + } + UNREACHABLE(); + } +#endif void lookahead::restore_clauses(literal l) { SASSERT(m_search_mode == lookahead_mode::searching); - // increase the length of clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; +#if OLD_NARY for (unsigned idx : m_nary[(~l).index()]) { if (sz-- == 0) break; ++m_nary_literals[idx]; } - +#else + for (nary* n : m_nary[(~l).index()]) { + if (sz-- == 0) break; + n->inc_size(); + } +#endif // add idx back to clause list where l is positive // add them back in the same order as they were inserted // in this way we can check that the clauses are the same. sz = m_nary_count[l.index()]; +#if OLD_NARY unsigned_vector const& pclauses = m_nary[l.index()]; for (unsigned i = sz; i > 0; ) { --i; @@ -1456,6 +1656,17 @@ namespace sat { } } } +#else + ptr_vector& pclauses = m_nary[l.index()]; + for (unsigned i = sz; i-- > 0; ) { + for (literal lit : *pclauses[i]) { + if (lit != l) { + // SASSERT(m_nary[lit.index()] == pclauses[i]); + m_nary_count[lit.index()]++; + } + } + } +#endif } void lookahead::propagate_clauses(literal l) { @@ -1527,7 +1738,7 @@ namespace sat { // Sum_{ clause C that contains ~l } 1 double lookahead::literal_occs(literal l) { double result = m_binary[l.index()].size(); - unsigned_vector const& nclauses = m_nary[(~l).index()]; + // unsigned_vector const& nclauses = m_nary[(~l).index()]; result += m_nary_count[(~l).index()]; result += m_ternary_count[(~l).index()]; return result; @@ -1684,7 +1895,7 @@ namespace sat { return false; #if 0 // no propagations are allowed to reduce clauses. - for (clause * cp : m_full_watches[l.index()]) { + for (nary * cp : m_nary[(~l).index()]) { clause& c = *cp; unsigned sz = c.size(); bool found = false; @@ -2026,6 +2237,7 @@ namespace sat { } } +#if OLD_NARY for (unsigned l_idx : m_nary_literals) { literal l = to_literal(l_idx); if (first) { @@ -2041,6 +2253,12 @@ namespace sat { out << l << " "; } } +#else + for (nary * n : m_nary_clauses) { + for (literal l : *n) out << l << " "; + out << "\n"; + } +#endif return out; } diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 9a50dceed..2972bc167 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,6 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ +#define OLD_NARY 0 #include "sat_elim_eqs.h" @@ -129,6 +130,36 @@ namespace sat { literal m_u, m_v; }; + class nary { + unsigned m_size; // number of non-false literals + size_t m_obj_size; // object size (counting all literals) + literal m_head; // head literal + literal m_literals[0]; // list of literals, put any true literal in head. + size_t num_lits() const { + return (m_obj_size - sizeof(nary)) / sizeof(literal); + } + public: + static size_t get_obj_size(unsigned sz) { return sizeof(nary) + sz * sizeof(literal); } + size_t obj_size() const { return m_obj_size; } + nary(unsigned sz, literal const* lits): + m_size(sz), + m_obj_size(get_obj_size(sz)) { + for (unsigned i = 0; i < sz; ++i) m_literals[i] = lits[i]; + m_head = lits[0]; + } + unsigned size() const { return m_size; } + unsigned dec_size() { SASSERT(m_size > 0); return --m_size; } + void inc_size() { SASSERT(m_size < num_lits()); ++m_size; } + literal get_head() const { return m_head; } + void set_head(literal l) { m_head = l; } + + literal operator[](unsigned i) { SASSERT(i < num_lits()); return m_literals[i]; } + literal const* begin() const { return m_literals; } + literal const* end() const { return m_literals + num_lits(); } + // swap the true literal to the head. + // void swap(unsigned i, unsigned j) { SASSERT(i < num_lits() && j < num_lits()); std::swap(m_literals[i], m_literals[j]); } + }; + struct cube_state { bool m_first; svector m_is_decision; @@ -160,11 +191,18 @@ namespace sat { vector> m_ternary; // lit |-> vector of ternary clauses unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit +#if OLD_NARY vector m_nary; // lit |-> vector of clause_id - unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_clauses2[lit] unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, // the first entry is the current length, clauses are separated by a null_literal +#else + small_object_allocator m_allocator; + vector> m_nary; // lit |-> vector of nary clauses + ptr_vector m_nary_clauses; // vector of all nary clauses +#endif + unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit] + unsigned m_num_tc1; unsigned_vector m_num_tc1_lim; unsigned m_qhead; // propagation queue head @@ -410,15 +448,20 @@ namespace sat { void propagate_clauses_searching(literal l); void propagate_clauses_lookahead(literal l); void restore_clauses(literal l); +#if OLD_NARY void remove_clause(literal l, unsigned clause_idx); void remove_clause_at(literal l, unsigned clause_idx); - +#else + void remove_clause(literal l, nary& n); + void remove_clause_at(literal l, nary& n); +#endif // ------------------------------------ // initialization void init_var(bool_var v); void init(); void copy_clauses(clause_vector const& clauses, bool learned); + nary * copy_clause(clause const& c); // ------------------------------------ // search @@ -499,6 +542,12 @@ namespace sat { ~lookahead() { m_s.rlimit().pop_child(); +#if OLD_NARY +#else + for (nary* n : m_nary_clauses) { + m_allocator.deallocate(n->obj_size(), n); + } +#endif } diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 497587cd3..c8cb7e2ee 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -3,11 +3,11 @@ Copyright (c) 2017 Microsoft Corporation Module Name: - parallel_solver.cpp + parallel_tactic.cpp Abstract: - Parallel solver in the style of Treengeling. + Parallel tactic in the style of Treengeling. It assumes a solver that supports good lookaheads. @@ -20,13 +20,183 @@ Notes: --*/ +#include "util/scoped_ptr_vector.h" #include "solver/solver.h" #include "tactic/tactic.h" class parallel_tactic : public tactic { - ref m_solver; + + // parameters + unsigned m_conflicts_lower_bound; + unsigned m_conflicts_upper_bound; + unsigned m_conflicts_growth_rate; + unsigned m_conflicts_decay_rate; + unsigned m_num_threads; + + unsigned m_max_conflicts; + + sref_vector m_solvers; + scoped_ptr_vector m_managers; + + void init() { + m_conflicts_lower_bound = 1000; + m_conflicts_upper_bound = 10000; + m_conflicts_growth_rate = 150; + m_conflicts_decay_rate = 75; + m_max_conflicts = m_conflicts_lower_bound; + m_num_threads = omp_get_num_threads(); + } + + unsigned get_max_conflicts() { + return m_max_conflicts; + } + + void set_max_conflicts(unsigned c) { + m_max_conflicts = c; + } + + bool should_increase_conflicts() { + NOT_IMPLEMENTED_YET(); + return false; + } + + int pick_solvers() { + NOT_IMPLEMENTED_YET(); + return 1; + } + + void update_max_conflicts() { + if (should_increase_conflicts()) { + set_max_conflicts(std::min(m_conflicts_upper_bound, m_conflicts_growth_rate * get_max_conflicts() / 100)); + } + else { + set_max_conflicts(std::max(m_conflicts_lower_bound, m_conflicts_decay_rate * get_max_conflicts() / 100)); + } + } + + lbool simplify(solver& s) { + params_ref p; + p.set_uint("sat.max_conflicts", 10); + p.set_bool("sat.lookahead_simplify", true); + s.updt_params(p); + lbool is_sat = s.check_sat(0,0); + p.set_uint("sat.max_conflicts", get_max_conflicts()); + p.set_bool("sat.lookahead_simplify", false); + s.updt_params(p); + return is_sat; + } + + lbool lookahead(solver& s) { + ast_manager& m = s.get_manager(); + params_ref p; + p.set_uint("sat.lookahead.cube.cutoff", 1); + expr_ref_vector cubes(m); + while (true) { + expr_ref c = s.cube(); + if (m.is_false(c)) { + break; + } + cubes.push_back(c); + } + if (cubes.empty()) { + return l_false; + } + for (unsigned i = 1; i < cubes.size(); ++i) { + ast_manager * new_m = alloc(ast_manager, m, !m.proof_mode()); + solver* s1 = s.translate(*new_m, params_ref()); + ast_translation translate(m, *new_m); + expr_ref cube(translate(cubes[i].get()), *new_m); + s1->assert_expr(cube); + + #pragma omp critical (_solvers) + { + m_managers.push_back(new_m); + m_solvers.push_back(s1); + } + } + s.assert_expr(cubes[0].get()); + return l_true; + } + + lbool solve(solver& s) { + params_ref p; + p.set_uint("sat.max_conflicts", get_max_conflicts()); + s.updt_params(p); + lbool is_sat = s.check_sat(0, 0); + return is_sat; + } + + void remove_unsat(svector& unsat) { + std::sort(unsat.begin(), unsat.end()); + unsat.reverse(); + DEBUG_CODE(for (unsigned i = 0; i + 1 < unsat.size(); ++i) SASSERT(unsat[i] > unsat[i+1]);); + for (int i : unsat) { + m_solvers.erase(i); + } + unsat.reset(); + } + + lbool solve() { + while (true) { + int sz = pick_solvers(); + + if (sz == 0) { + return l_false; + } + svector unsat; + int sat_index = -1; + + // Simplify phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = simplify(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: sat_index = i; break; + case l_undef: break; + } + } + if (sat_index != -1) return l_true; // TBD: extact model + sz -= unsat.size(); + remove_unsat(unsat); + if (sz == 0) continue; + + // Solve phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = solve(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: sat_index = i; break; + case l_undef: break; + } + } + if (sat_index != -1) return l_true; // TBD: extact model + sz -= unsat.size(); + remove_unsat(unsat); + if (sz == 0) continue; + + // Split phase. + #pragma omp parallel for + for (int i = 0; i < sz; ++i) { + lbool is_sat = lookahead(*m_solvers[i]); + switch (is_sat) { + case l_false: unsat.push_back(i); break; + case l_true: break; + case l_undef: break; + } + } + remove_unsat(unsat); + + update_max_conflicts(); + } + return l_undef; + } + public: - parallel_tactic(solver* s) : m_solver(s) {} + parallel_tactic(solver* s) { + m_solvers.push_back(s); // clone it? + } void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { NOT_IMPLEMENTED_YET(); From 09ea370ea33f64e54f9cd837cd4e9f66ebe933df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Oct 2017 12:06:19 -0700 Subject: [PATCH 61/67] update C-example that fails to not use longjumps. Issue #1297 Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 35 ++++++++++++++++++++++++----------- src/api/api_parsers.cpp | 16 ++++++++-------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 88fdaa1cf..6327ad40f 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -65,6 +65,15 @@ void throw_z3_error(Z3_context c, Z3_error_code e) longjmp(g_catch_buffer, e); } +/** + \brief Error handling that depends on checking an error code on the context. + +*/ + +void nothrow_z3_error(Z3_context c, Z3_error_code e) { + // no-op +} + /** \brief Create a logical context. @@ -1592,18 +1601,16 @@ void error_code_example1() void error_code_example2() { Z3_config cfg; Z3_context ctx = NULL; - int r; + Z3_error_code e; printf("\nerror_code_example2\n"); LOG_MSG("error_code_example2"); - /* low tech try&catch */ - r = setjmp(g_catch_buffer); - if (r == 0) { + if (1) { Z3_ast x, y, app; cfg = Z3_mk_config(); - ctx = mk_context_custom(cfg, throw_z3_error); + ctx = mk_context_custom(cfg, nothrow_z3_error); Z3_del_config(cfg); x = mk_int_var(ctx, "x"); @@ -1611,11 +1618,14 @@ void error_code_example2() { printf("before Z3_mk_iff\n"); /* the next call will produce an error */ app = Z3_mk_iff(ctx, x, y); + e = Z3_get_error_code(ctx); + if (e != Z3_OK) goto err; unreachable(); Z3_del_context(ctx); } else { - printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); + err: + printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { Z3_del_context(ctx); } @@ -1781,15 +1791,14 @@ void parser_example5() { Z3_config cfg; Z3_context ctx = NULL; Z3_solver s = NULL; - int r; + Z3_error_code e; printf("\nparser_example5\n"); LOG_MSG("parser_example5"); - r = setjmp(g_catch_buffer); - if (r == 0) { + if (1) { cfg = Z3_mk_config(); - ctx = mk_context_custom(cfg, throw_z3_error); + ctx = mk_context_custom(cfg, nothrow_z3_error); s = mk_solver(ctx); Z3_del_config(cfg); @@ -1798,12 +1807,15 @@ void parser_example5() { "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", 0, 0, 0, 0, 0, 0); + e = Z3_get_error_code(ctx); + if (e != Z3_OK) goto err; unreachable(); del_solver(ctx, s); Z3_del_context(ctx); } else { - printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, (Z3_error_code)r)); + err: + printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { printf("Error message: '%s'.\n",Z3_get_smtlib_error(ctx)); del_solver(ctx, s); @@ -2639,6 +2651,7 @@ void smt2parser_example() { ctx = mk_context(); fs = Z3_parse_smtlib2_string(ctx, "(declare-fun a () (_ BitVec 8)) (assert (bvuge a #x10)) (assert (bvule a #xf0))", 0, 0, 0, 0, 0, 0); printf("formulas: %s\n", Z3_ast_to_string(ctx, fs)); + Z3_del_context(ctx); } diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index 7a68efbd8..71fa945d3 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -56,20 +56,20 @@ extern "C" { Z3_func_decl const decls[]) { Z3_TRY; LOG_Z3_parse_smtlib_string(c, str, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - std::ostringstream outs; + std::ostringstream* outs = alloc(std::ostringstream); bool ok = false; RESET_ERROR_CODE(); init_smtlib_parser(c, num_sorts, sort_names, sorts, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(outs); + mk_c(c)->m_smtlib_parser->set_error_stream(*outs); try { ok = mk_c(c)->m_smtlib_parser->parse_string(str); } catch (...) { ok = false; } - mk_c(c)->m_smtlib_error_buffer = outs.str(); - outs.clear(); + mk_c(c)->m_smtlib_error_buffer = outs->str(); + dealloc(outs); if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); @@ -89,17 +89,17 @@ extern "C" { LOG_Z3_parse_smtlib_file(c, file_name, num_sorts, sort_names, types, num_decls, decl_names, decls); bool ok = false; RESET_ERROR_CODE(); - std::ostringstream outs; + std::ostringstream* outs = alloc(std::ostringstream); init_smtlib_parser(c, num_sorts, sort_names, types, num_decls, decl_names, decls); - mk_c(c)->m_smtlib_parser->set_error_stream(outs); + mk_c(c)->m_smtlib_parser->set_error_stream(*outs); try { ok = mk_c(c)->m_smtlib_parser->parse_file(file_name); } catch(...) { ok = false; } - mk_c(c)->m_smtlib_error_buffer = outs.str(); - outs.clear(); + mk_c(c)->m_smtlib_error_buffer = outs->str(); + dealloc(outs); if (!ok) { mk_c(c)->reset_parser(); SET_ERROR_CODE(Z3_PARSER_ERROR); From 97f37613c2915f6270fd5d6f82057e1382a5a1cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 07:50:04 -0700 Subject: [PATCH 62/67] parallel Signed-off-by: Nikolaj Bjorner --- src/tactic/portfolio/parallel_tactic.cpp | 116 +++++++++++++++-------- src/tactic/portfolio/parallel_tactic.h | 6 +- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 5cd508042..1ee6cbfef 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -30,19 +30,16 @@ Notes: class parallel_tactic : public tactic { class solver_state { + scoped_ptr m_manager; ref m_solver; expr_ref_vector m_cube; unsigned m_units; public: - solver_state(solver* s): m_solver(s), m_cube(s->get_manager()), m_units(0) {} - - solver_state& operator=(solver_state& other) { - m_solver = other.m_solver; - m_cube.reset(); - m_cube.append(other.m_cube); - m_units = other.m_units; - return *this; - } + solver_state(ast_manager* m, solver* s): + m_manager(m), + m_solver(s), + m_cube(s->get_manager()), + m_units(0) {} void update_units() { m_units = 0; @@ -66,6 +63,21 @@ class parallel_tactic : public tactic { solver& get_solver() { return *m_solver; } solver const& get_solver() const { return *m_solver; } + + solver_state* clone(params_ref& p, expr* cube) { + ast_manager& m = m_solver->get_manager(); + ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); + solver* s = m_solver->translate(*new_m, p); + solver_state* st = alloc(solver_state, new_m, s); + ast_translation translate(m, *new_m); + for (expr* c : m_cube) { + st->m_cube.push_back(translate(c)); + } + expr_ref cube1(translate(cube), *new_m); + st->m_cube.push_back(cube1); + s->assert_expr(cube1); + return st; + } }; public: @@ -74,7 +86,8 @@ public: } private: - ast_manager* m_manager; + ast_manager& m_manager; + params_ref m_params; // parameters unsigned m_conflicts_lower_bound; @@ -84,11 +97,10 @@ private: unsigned m_num_threads; double m_progress; - unsigned m_max_conflicts; + unsigned m_max_conflicts; statistics m_stats; vector m_solvers; - scoped_ptr_vector m_managers; void init() { m_conflicts_lower_bound = 1000; @@ -114,6 +126,9 @@ private: void update_progress(bool b) { m_progress = 0.9 * m_progress + (b ? 1 : -1); + if (b) { + m_stats.update("closed", 1u); + } } int pick_solvers() { @@ -157,6 +172,7 @@ private: lbool simplify(solver& s) { params_ref p; + p.copy(m_params); p.set_uint("sat.max_conflicts", 10); p.set_bool("sat.lookahead_simplify", true); s.updt_params(p); @@ -170,6 +186,7 @@ private: void cube(solver& s, expr_ref_vector& cubes) { ast_manager& m = s.get_manager(); params_ref p; + p.copy(m_params); p.set_uint("sat.lookahead.cube.cutoff", 1); s.updt_params(p); while (true) { @@ -177,12 +194,18 @@ private: if (m.is_false(c)) { break; } + if (m.is_true(c)) { + cubes.reset(); + cubes.push_back(c); + break; + } cubes.push_back(c); } } lbool solve(solver& s) { params_ref p; + p.copy(m_params); p.set_uint("sat.max_conflicts", get_max_conflicts()); s.updt_params(p); return s.check_sat(0, 0); @@ -199,6 +222,7 @@ private: m_solvers[j - 1] = m_solvers[j]; } m_solvers.shrink(m_solvers.size() - 1); + update_progress(true); } unsat.reset(); } @@ -206,7 +230,7 @@ private: void get_model(model_ref& mdl, int sat_index) { SASSERT(sat_index != -1); m_solvers[sat_index]->get_solver().get_model(mdl); - ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), *m_manager); + ast_translation translate(m_solvers[sat_index]->get_solver().get_manager(), m_manager); mdl = mdl->translate(translate); } @@ -226,9 +250,17 @@ private: for (int i = 0; i < sz; ++i) { lbool is_sat = simplify(m_solvers[i]->get_solver()); switch (is_sat) { - case l_false: unsat.push_back(i); break; - case l_true: sat_index = i; break; - case l_undef: break; + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + case l_true: + sat_index = i; + break; + case l_undef: + break; } } if (sat_index != -1) { @@ -245,9 +277,21 @@ private: for (int i = 0; i < sz; ++i) { lbool is_sat = solve(m_solvers[i]->get_solver()); switch (is_sat) { - case l_false: update_progress(true); unsat.push_back(i); break; - case l_true: sat_index = i; break; - case l_undef: update_progress(false); break; + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + case l_true: + sat_index = i; + break; + case l_undef: + #pragma omp critical (parallel_tactic) + { + update_progress(false); + } + break; } } if (sat_index != -1) { @@ -279,16 +323,11 @@ private: } solver& s = m_solvers[i]->get_solver(); ast_manager& m = s.get_manager(); + if (cubes[i].size() == 1 && m.is_true(cubes[i][0].get())) { + continue; + } for (unsigned j = 1; j < cubes[i].size(); ++j) { - ast_manager * new_m = alloc(ast_manager, m, !m.proof_mode()); - solver* s1 = s.translate(*new_m, params_ref()); - ast_translation translate(m, *new_m); - expr_ref cube(translate(cubes[i][j].get()), *new_m); - s1->assert_expr(cube); - m_managers.push_back(new_m); - solver_state* st = alloc(solver_state, s1); - st->add_cube(cube); - m_solvers.push_back(st); + m_solvers.push_back(m_solvers[i]->clone(m_params, cubes[i][j].get())); } expr* cube0 = cubes[i][0].get(); m_solvers[i]->add_cube(cube0); @@ -305,22 +344,22 @@ private: out << "solver units" << s->num_units() << "\n"; out << "cube " << s->cube() << "\n"; } + m_stats.display(out); return out; } public: - parallel_tactic() : - m_manager(0) { + parallel_tactic(ast_manager& m, params_ref const& p) : + m_manager(m), + m_params(p) { init(); } void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { ast_manager& m = g->m(); - m_manager = &m; - params_ref p; - solver* s = mk_fd_solver(m, p); - m_solvers.push_back(alloc(solver_state, s)); + solver* s = mk_fd_solver(m, m_params); + m_solvers.push_back(alloc(solver_state, 0, s)); expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; @@ -359,15 +398,14 @@ public: for (solver_state * s : m_solvers) dealloc(s); m_solvers.reset(); init(); - m_manager = nullptr; } tactic* translate(ast_manager& m) { - return alloc(parallel_tactic); + return alloc(parallel_tactic, m, m_params); } virtual void updt_params(params_ref const & p) { - // TBD + m_params.copy(p); } virtual void collect_param_descrs(param_descrs & r) { // TBD @@ -385,7 +423,7 @@ public: }; -tactic * mk_parallel_tactic() { - return alloc(parallel_tactic); +tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p) { + return alloc(parallel_tactic, m, p); } diff --git a/src/tactic/portfolio/parallel_tactic.h b/src/tactic/portfolio/parallel_tactic.h index 063d1480f..8fd9a29fa 100644 --- a/src/tactic/portfolio/parallel_tactic.h +++ b/src/tactic/portfolio/parallel_tactic.h @@ -22,6 +22,10 @@ Notes: class solver; class tactic; -tactic * mk_parallel_tactic(); +tactic * mk_parallel_tactic(ast_manager& m, params_ref const& p); + +/* + ADD_TACTIC("qffdp", "builtin strategy for solving QF_FD problems in parallel.", "mk_parallel_tactic(m, p)") +*/ #endif From 79ceaa1d1394d7b51e5c1b90c98c64188776509e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 13:17:57 -0700 Subject: [PATCH 63/67] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 4 +- src/sat/tactic/goal2sat.cpp | 29 +++--- src/tactic/portfolio/CMakeLists.txt | 1 + src/tactic/portfolio/parallel_tactic.cpp | 116 +++++++++++++---------- 4 files changed, 89 insertions(+), 61 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 4447b399c..3812eff56 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1468,11 +1468,14 @@ namespace sat { lh.simplify(); lh.collect_statistics(m_aux_stats); } +#if 0 + // Buggy { lookahead lh(*this); lh.scc(); lh.collect_statistics(m_aux_stats); } +#endif } @@ -3049,7 +3052,6 @@ namespace sat { m_probing.updt_params(p); m_scc.updt_params(p); m_rand.set_seed(m_config.m_random_seed); - m_step_size = m_config.m_step_size_init; } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 75561ed86..81302764a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -94,6 +94,12 @@ struct goal2sat::imp { std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator"; throw tactic_exception(s0.c_str()); } + + sat::bool_var mk_var(expr* t, bool ext) { + sat::bool_var v = m_solver.mk_var(ext); + m_map.insert(t, v); + return v; + } void mk_clause(sat::literal l) { TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); @@ -120,7 +126,7 @@ struct goal2sat::imp { sat::bool_var mk_true() { if (m_true == sat::null_bool_var) { // create fake variable to represent true; - m_true = m_solver.mk_var(); + m_true = mk_var(m.mk_true(), false); mk_clause(sat::literal(m_true, false)); // v is true } return m_true; @@ -139,8 +145,7 @@ struct goal2sat::imp { } else { bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); - sat::bool_var v = m_solver.mk_var(ext); - m_map.insert(t, v); + sat::bool_var v = mk_var(t, ext); l = sat::literal(v, sign); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { @@ -247,7 +252,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); sat::literal * lits = m_result_stack.end() - num; @@ -286,7 +291,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); // l => /\ lits @@ -330,7 +335,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(n, false); sat::literal l(k, false); m_cache.insert(n, l); mk_clause(~l, ~c, t); @@ -367,7 +372,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = m_solver.mk_var(); + sat::bool_var k = mk_var(t, false); sat::literal l(k, false); m_cache.insert(t, l); mk_clause(~l, l1, ~l2); @@ -392,7 +397,7 @@ struct goal2sat::imp { } sat::literal_vector lits; convert_pb_args(num, lits); - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); ensure_extension(); if (lits.size() % 2 == 0) lits[0].neg(); m_ext->add_xor(v, lits); @@ -451,7 +456,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -476,7 +481,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -525,7 +530,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -547,7 +552,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } else { - sat::bool_var v = m_solver.mk_var(true); + sat::bool_var v = mk_var(t, true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_result_stack.shrink(sz - t->get_num_args()); diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index c4ae795c6..055251467 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -21,4 +21,5 @@ z3_add_component(portfolio TACTIC_HEADERS default_tactic.h fd_solver.h + parallel_tactic.h ) diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 1ee6cbfef..524754613 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -30,12 +30,14 @@ Notes: class parallel_tactic : public tactic { class solver_state { + params_ref m_params; scoped_ptr m_manager; ref m_solver; expr_ref_vector m_cube; unsigned m_units; public: - solver_state(ast_manager* m, solver* s): + solver_state(ast_manager* m, solver* s, params_ref const& p): + m_params(p), m_manager(m), m_solver(s), m_cube(s->get_manager()), @@ -49,6 +51,7 @@ class parallel_tactic : public tactic { for (unsigned i = st.size(); i-- > 0; ) { if (st.get_key(i) == units) { m_units = st.get_uint_value(i); + std::cout << "value for " << i << " is " << m_units << "\n"; break; } } @@ -64,15 +67,17 @@ class parallel_tactic : public tactic { solver const& get_solver() const { return *m_solver; } - solver_state* clone(params_ref& p, expr* cube) { + params_ref const& params() const { return m_params; } + + solver_state* clone(params_ref const& p, expr* cube) { ast_manager& m = m_solver->get_manager(); ast_manager* new_m = alloc(ast_manager, m, !m.proof_mode()); solver* s = m_solver->translate(*new_m, p); - solver_state* st = alloc(solver_state, new_m, s); + solver_state* st = alloc(solver_state, new_m, s, m_params); ast_translation translate(m, *new_m); for (expr* c : m_cube) { st->m_cube.push_back(translate(c)); - } + } expr_ref cube1(translate(cube), *new_m); st->m_cube.push_back(cube1); s->assert_expr(cube1); @@ -109,7 +114,7 @@ private: m_conflicts_decay_rate = 75; m_max_conflicts = m_conflicts_lower_bound; m_progress = 0; - m_num_threads = omp_get_num_threads(); // TBD adjust by possible threads used inside each solver. + m_num_threads = omp_get_num_procs(); // TBD adjust by possible threads used inside each solver. } unsigned get_max_conflicts() { @@ -173,40 +178,60 @@ private: lbool simplify(solver& s) { params_ref p; p.copy(m_params); - p.set_uint("sat.max_conflicts", 10); - p.set_bool("sat.lookahead_simplify", true); + p.set_uint("max_conflicts", 10); + p.set_bool("lookahead_simplify", true); s.updt_params(p); lbool is_sat = s.check_sat(0,0); - p.set_uint("sat.max_conflicts", get_max_conflicts()); - p.set_bool("sat.lookahead_simplify", false); + p.set_uint("max_conflicts", get_max_conflicts()); + p.set_bool("lookahead_simplify", false); s.updt_params(p); return is_sat; } - void cube(solver& s, expr_ref_vector& cubes) { - ast_manager& m = s.get_manager(); - params_ref p; - p.copy(m_params); - p.set_uint("sat.lookahead.cube.cutoff", 1); - s.updt_params(p); + lbool cube(solver_state& s) { + ast_manager& m = s.get_solver().get_manager(); + expr_ref_vector cubes(m); + params_ref p; + p.copy(s.params()); + p.set_uint("lookahead.cube.cutoff", 1); + s.get_solver().updt_params(p); + SASSERT(&m == &cubes.get_manager()); while (true) { - expr_ref c = s.cube(); - if (m.is_false(c)) { + expr_ref c = s.get_solver().cube(); + VERIFY(c); + if (m.is_false(c)) { break; } if (m.is_true(c)) { cubes.reset(); - cubes.push_back(c); - break; + return l_undef; } cubes.push_back(c); } + + IF_VERBOSE(1, verbose_stream() << "cubes: " << cubes << "\n";); + + if (cubes.empty()) { + return l_false; + } + for (unsigned j = 1; j < cubes.size(); ++j) { + solver_state* s1 = s.clone(s.params(), cubes[j].get()); + #pragma omp critical (parallel_tactic) + { + m_solvers.push_back(s1); + } + } + + expr* cube0 = cubes[0].get(); + s.add_cube(cube0); + s.get_solver().assert_expr(cube0); + return l_undef; } lbool solve(solver& s) { params_ref p; p.copy(m_params); - p.set_uint("sat.max_conflicts", get_max_conflicts()); + p.set_uint("max_conflicts", get_max_conflicts()); s.updt_params(p); return s.check_sat(0, 0); } @@ -238,6 +263,7 @@ private: while (true) { int sz = pick_solvers(); + if (sz == 0) { return l_false; } @@ -246,6 +272,8 @@ private: // Simplify phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :simplify " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { lbool is_sat = simplify(m_solvers[i]->get_solver()); @@ -273,6 +301,8 @@ private: // Solve phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :solve " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { lbool is_sat = solve(m_solvers[i]->get_solver()); @@ -287,10 +317,6 @@ private: sat_index = i; break; case l_undef: - #pragma omp critical (parallel_tactic) - { - update_progress(false); - } break; } } @@ -304,35 +330,29 @@ private: sz = std::min(max_num_splits(), sz); if (sz == 0) continue; - vector cubes; - for (int i = 0; i < sz; ++i) { - cubes.push_back(expr_ref_vector(m_solvers[i]->get_solver().get_manager())); - } // Split phase. IF_VERBOSE(1, verbose_stream() << "(solver.parallel :split " << sz << ")\n";); + IF_VERBOSE(1, display(verbose_stream()); verbose_stream() << "Number of solvers: " << sz << "\n";); + #pragma omp parallel for for (int i = 0; i < sz; ++i) { - cube(m_solvers[i]->get_solver(), cubes[i]); + switch (cube(*m_solvers[i])) { + case l_false: + #pragma omp critical (parallel_tactic) + { + unsat.push_back(i); + } + break; + default: + #pragma omp critical (parallel_tactic) + { + update_progress(false); + } + break; + } } - for (int i = 0; i < sz; ++i) { - if (cubes[i].empty()) { - unsat.push_back(i); - continue; - } - solver& s = m_solvers[i]->get_solver(); - ast_manager& m = s.get_manager(); - if (cubes[i].size() == 1 && m.is_true(cubes[i][0].get())) { - continue; - } - for (unsigned j = 1; j < cubes[i].size(); ++j) { - m_solvers.push_back(m_solvers[i]->clone(m_params, cubes[i][j].get())); - } - expr* cube0 = cubes[i][0].get(); - m_solvers[i]->add_cube(cube0); - s.assert_expr(cube0); - } remove_unsat(unsat); update_max_conflicts(); } @@ -341,7 +361,7 @@ private: std::ostream& display(std::ostream& out) { for (solver_state* s : m_solvers) { - out << "solver units" << s->num_units() << "\n"; + out << "solver units " << s->num_units() << "\n"; out << "cube " << s->cube() << "\n"; } m_stats.display(out); @@ -359,7 +379,7 @@ public: void operator ()(const goal_ref & g,goal_ref_buffer & result,model_converter_ref & mc,proof_converter_ref & pc,expr_dependency_ref & dep) { ast_manager& m = g->m(); solver* s = mk_fd_solver(m, m_params); - m_solvers.push_back(alloc(solver_state, 0, s)); + m_solvers.push_back(alloc(solver_state, 0, s, m_params)); expr_ref_vector clauses(m); ptr_vector assumptions; obj_map bool2dep; From 81ad69214c15831076beaa6839546ebbe099e698 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 17:06:28 -0700 Subject: [PATCH 64/67] fixing lookahead/ba + parallel Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 5 ++++ src/sat/sat_lookahead.cpp | 29 ++++++++++++++++++------ src/sat/sat_lookahead.h | 3 ++- src/sat/sat_solver.cpp | 8 ++++--- src/sat/sat_solver.h | 2 +- src/sat/sat_solver/inc_sat_solver.cpp | 6 ++++- src/sat/tactic/goal2sat.cpp | 29 ++++++++++-------------- src/tactic/portfolio/parallel_tactic.cpp | 3 +-- 8 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 6a68c30c9..a2058512b 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -300,6 +300,10 @@ namespace sat { void ba_solver::set_conflict(constraint& c, literal lit) { m_stats.m_num_conflicts++; TRACE("ba", display(tout, c, true); ); + if (!validate_conflict(c)) { + display(std::cout, c, true); + UNREACHABLE(); + } SASSERT(validate_conflict(c)); if (c.is_xor() && value(lit) == l_true) lit.neg(); SASSERT(value(lit) == l_false); @@ -645,6 +649,7 @@ namespace sat { display(verbose_stream(), p, true); verbose_stream() << "alit: " << alit << "\n"; verbose_stream() << "num watch " << num_watch << "\n"); + UNREACHABLE(); exit(0); return l_undef; } diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 0374aca9c..d0f4bc7f6 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -92,7 +92,7 @@ namespace sat { // TRACE("sat", display(tout << "Delete " << to_literal(idx) << "\n");); literal_vector & lits = m_binary[idx]; SASSERT(!lits.empty()); - literal l = lits.back(); + literal l = lits.back(); lits.pop_back(); SASSERT(!m_binary[(~l).index()].empty()); IF_VERBOSE(0, if (m_binary[(~l).index()].back() != ~to_literal(idx)) verbose_stream() << "pop bad literal: " << idx << " " << (~l).index() << "\n";); @@ -641,18 +641,18 @@ namespace sat { void lookahead::init_arcs(literal l) { literal_vector lits; literal_vector const& succ = m_binary[l.index()]; - for (unsigned i = 0; i < succ.size(); ++i) { - literal u = succ[i]; + for (literal u : succ) { SASSERT(u != l); + // l => u if (u.index() > l.index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } } for (auto w : m_watches[l.index()]) { - if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { + if (w.is_ext_constraint() && m_s.m_ext->is_extended_binary(w.get_ext_constraint_idx(), lits)) { for (literal u : lits) { - if (u.index() > l.index() && is_stamped(u)) { + if (u.index() > (~l).index() && is_stamped(u)) { add_arc(~l, ~u); add_arc( u, l); } @@ -1298,6 +1298,8 @@ namespace sat { watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); for (; it != end && !inconsistent(); ++it) { SASSERT(it->get_kind() == watched::EXT_CONSTRAINT); + VERIFY(is_true(l)); + VERIFY(!is_undef(l)); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { lookahead_literal_occs_fun literal_occs_fn(*this); @@ -1704,6 +1706,8 @@ namespace sat { } void lookahead::propagate_clauses(literal l) { + VERIFY(is_true(l)); + VERIFY(value(l) == l_true); propagate_ternary(l); switch (m_search_mode) { case lookahead_mode::searching: @@ -1713,6 +1717,9 @@ namespace sat { propagate_clauses_lookahead(l); break; } + VERIFY(!is_undef(l)); + VERIFY(is_true(l)); + VERIFY(value(l) == l_true); propagate_external(l); } @@ -2179,8 +2186,10 @@ namespace sat { lbool lookahead::cube() { literal_vector lits; + bool_var_vector vars; + for (bool_var v : m_freevars) vars.push_back(v); while (true) { - lbool result = cube(lits); + lbool result = cube(vars, lits); if (lits.empty() || result != l_undef) { return l_undef; } @@ -2189,8 +2198,13 @@ namespace sat { return l_undef; } - lbool lookahead::cube(literal_vector& lits) { + lbool lookahead::cube(bool_var_vector const& vars, literal_vector& lits) { + scoped_ext _scoped_ext(*this); lits.reset(); + m_select_lookahead_vars.reset(); + for (auto v : vars) { + m_select_lookahead_vars.insert(v); + } bool is_first = m_cube_state.m_first; if (is_first) { init_search(); @@ -2412,6 +2426,7 @@ namespace sat { \brief simplify set of clauses by extracting units from a lookahead at base level. */ void lookahead::simplify() { + scoped_ext _scoped_ext(*this); SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); m_search_mode = lookahead_mode::searching; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 38f9b0481..6ff228427 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -571,9 +571,10 @@ namespace sat { If cut-depth != 0, then it is used to control the depth of cuts. Otherwise, cut-fraction gives an adaptive threshold for creating cuts. */ + lbool cube(); - lbool cube(literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits); literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 3812eff56..8004c9635 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -162,6 +162,7 @@ namespace sat { m_user_scope_literals.append(src.m_user_scope_literals); m_mc = src.m_mc; + m_stats.m_units = init_trail_size(); } // ----------------------- @@ -837,11 +838,11 @@ namespace sat { return lh.select_lookahead(assumptions, vars); } - lbool solver::cube(literal_vector& lits) { + lbool solver::cube(bool_var_vector const& vars, literal_vector& lits) { if (!m_cuber) { m_cuber = alloc(lookahead, *this); } - lbool result = m_cuber->cube(lits); + lbool result = m_cuber->cube(vars, lits); if (result == l_false) { dealloc(m_cuber); m_cuber = nullptr; @@ -858,6 +859,7 @@ namespace sat { lbool solver::check(unsigned num_lits, literal const* lits) { init_reason_unknown(); pop_to_base_level(); + m_stats.m_units = init_trail_size(); IF_VERBOSE(2, verbose_stream() << "(sat.sat-solver)\n";); SASSERT(at_base_lvl()); if (m_config.m_dimacs_display) { @@ -4039,7 +4041,7 @@ namespace sat { } void stats::reset() { - memset(this, sizeof(*this), 0); + memset(this, 0, sizeof(*this)); } void mk_stat::display(std::ostream & out) const { diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index fa095623f..020c1dc42 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -365,7 +365,7 @@ namespace sat { char const* get_reason_unknown() const { return m_reason_unknown.c_str(); } literal select_lookahead(literal_vector const& assumptions, bool_var_vector const& vars); - lbool cube(literal_vector& lits); + lbool cube(bool_var_vector const& vars, literal_vector& lits); protected: unsigned m_conflicts_since_init; diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 908e56da8..53383a7c2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -353,8 +353,12 @@ public: m_internalized = true; } convert_internalized(); + sat::bool_var_vector vars; + for (auto& kv : m_map) { + vars.push_back(kv.m_value); + } sat::literal_vector lits; - lbool result = m_solver.cube(lits); + lbool result = m_solver.cube(vars, lits); if (result == l_false || lits.empty()) { return expr_ref(m.mk_false(), m); } diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 81302764a..3db2908ed 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -94,12 +94,6 @@ struct goal2sat::imp { std::string s0 = "operator " + s + " not supported, apply simplifier before invoking translator"; throw tactic_exception(s0.c_str()); } - - sat::bool_var mk_var(expr* t, bool ext) { - sat::bool_var v = m_solver.mk_var(ext); - m_map.insert(t, v); - return v; - } void mk_clause(sat::literal l) { TRACE("goal2sat", tout << "mk_clause: " << l << "\n";); @@ -126,7 +120,7 @@ struct goal2sat::imp { sat::bool_var mk_true() { if (m_true == sat::null_bool_var) { // create fake variable to represent true; - m_true = mk_var(m.mk_true(), false); + m_true = m_solver.mk_var(false); mk_clause(sat::literal(m_true, false)); // v is true } return m_true; @@ -145,7 +139,8 @@ struct goal2sat::imp { } else { bool ext = m_default_external || !is_uninterp_const(t) || m_interface_vars.contains(t); - sat::bool_var v = mk_var(t, ext); + sat::bool_var v = m_solver.mk_var(ext); + m_map.insert(t, v); l = sat::literal(v, sign); TRACE("sat", tout << "new_var: " << v << ": " << mk_ismt2_pp(t, m) << "\n";); if (ext && !is_uninterp_const(t)) { @@ -252,7 +247,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); sat::literal * lits = m_result_stack.end() - num; @@ -291,7 +286,7 @@ struct goal2sat::imp { } else { SASSERT(num <= m_result_stack.size()); - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); // l => /\ lits @@ -335,7 +330,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = mk_var(n, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(n, l); mk_clause(~l, ~c, t); @@ -372,7 +367,7 @@ struct goal2sat::imp { m_result_stack.reset(); } else { - sat::bool_var k = mk_var(t, false); + sat::bool_var k = m_solver.mk_var(); sat::literal l(k, false); m_cache.insert(t, l); mk_clause(~l, l1, ~l2); @@ -397,7 +392,7 @@ struct goal2sat::imp { } sat::literal_vector lits; convert_pb_args(num, lits); - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); ensure_extension(); if (lits.size() % 2 == 0) lits[0].neg(); m_ext->add_xor(v, lits); @@ -456,7 +451,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -481,7 +476,7 @@ struct goal2sat::imp { m_ext->add_pb_ge(sat::null_bool_var, wlits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_pb_ge(v, wlits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -530,7 +525,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, k.get_unsigned()); TRACE("goal2sat", tout << "root: " << root << " lit: " << lit << "\n";); @@ -552,7 +547,7 @@ struct goal2sat::imp { m_ext->add_at_least(sat::null_bool_var, lits, lits.size() - k.get_unsigned()); } else { - sat::bool_var v = mk_var(t, true); + sat::bool_var v = m_solver.mk_var(true); sat::literal lit(v, sign); m_ext->add_at_least(v, lits, lits.size() - k.get_unsigned()); m_result_stack.shrink(sz - t->get_num_args()); diff --git a/src/tactic/portfolio/parallel_tactic.cpp b/src/tactic/portfolio/parallel_tactic.cpp index 524754613..9bacbe6a0 100644 --- a/src/tactic/portfolio/parallel_tactic.cpp +++ b/src/tactic/portfolio/parallel_tactic.cpp @@ -398,7 +398,6 @@ public: mc = concat(fmc.get(), mc.get()); } g->reset(); - result.push_back(g.get()); break; case l_false: SASSERT(!g->proofs_enabled()); @@ -409,9 +408,9 @@ public: if (m.canceled()) { throw tactic_exception(Z3_CANCELED_MSG); } - result.push_back(g.get()); break; } + result.push_back(g.get()); } void cleanup() { From 99b232a4c54b93da68a39f2a17a12fd0c6410505 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Oct 2017 17:30:21 -0700 Subject: [PATCH 65/67] fix lookahead with ba extension Signed-off-by: Nikolaj Bjorner --- src/sat/ba_solver.cpp | 16 +++++++++++++--- src/sat/ba_solver.h | 4 +++- src/sat/sat_extension.h | 1 + src/sat/sat_lookahead.cpp | 6 ++++++ src/sat/sat_lookahead.h | 3 +++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index a2058512b..e0c1b1696 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1564,7 +1564,7 @@ namespace sat { init_watch(*c, true); } else { - s().set_external(lit.var()); + if (m_solver) m_solver->set_external(lit.var()); watch_literal(lit, *c); watch_literal(~lit, *c); } @@ -3243,6 +3243,18 @@ namespace sat { extension* ba_solver::copy(solver* s) { ba_solver* result = alloc(ba_solver); result->set_solver(s); + copy_core(result); + return result; + } + + extension* ba_solver::copy(lookahead* s) { + ba_solver* result = alloc(ba_solver); + result->set_lookahead(s); + copy_core(result); + return result; + } + + void ba_solver::copy_core(ba_solver* result) { literal_vector lits; svector wlits; for (constraint* cp : m_constraints) { @@ -3274,8 +3286,6 @@ namespace sat { UNREACHABLE(); } } - - return result; } void ba_solver::init_use_list(ext_use_list& ul) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 360f276f2..3e02d49dc 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -369,7 +369,7 @@ namespace sat { inline watch_list const& get_wlist(literal l) const { return m_lookahead ? m_lookahead->get_wlist(l) : m_solver->get_wlist(l); } inline void assign(literal l, justification j) { if (m_lookahead) m_lookahead->assign(l); else m_solver->assign(l, j); } inline void set_conflict(justification j, literal l) { if (m_lookahead) m_lookahead->set_conflict(); else m_solver->set_conflict(j, l); } - inline config const& get_config() const { return m_solver->get_config(); } + inline config const& get_config() const { return m_lookahead ? m_lookahead->get_config() : m_solver->get_config(); } inline void drat_add(literal_vector const& c, svector const& premises) { m_solver->m_drat.add(c, premises); } @@ -428,6 +428,7 @@ namespace sat { constraint* add_pb_ge(literal l, svector const& wlits, unsigned k, bool learned); constraint* add_xor(literal l, literal_vector const& lits, bool learned); + void copy_core(ba_solver* result); public: ba_solver(); virtual ~ba_solver(); @@ -453,6 +454,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const; virtual void collect_statistics(statistics& st) const; virtual extension* copy(solver* s); + virtual extension* copy(lookahead* s); virtual void find_mutexes(literal_vector& lits, vector & mutexes); virtual void pop_reinit(); virtual void gc(); diff --git a/src/sat/sat_extension.h b/src/sat/sat_extension.h index 1f747ae50..c2a9197c1 100644 --- a/src/sat/sat_extension.h +++ b/src/sat/sat_extension.h @@ -71,6 +71,7 @@ namespace sat { virtual std::ostream& display_justification(std::ostream& out, ext_justification_idx idx) const = 0; virtual void collect_statistics(statistics& st) const = 0; virtual extension* copy(solver* s) = 0; + virtual extension* copy(lookahead* s) = 0; virtual void find_mutexes(literal_vector& lits, vector & mutexes) = 0; virtual void gc() = 0; virtual void pop_reinit() = 0; diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index d0f4bc7f6..11c946fba 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -988,6 +988,7 @@ namespace sat { } } +#if 0 // copy externals: for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { watch_list const& wl = m_s.m_watches[idx]; @@ -997,6 +998,11 @@ namespace sat { } } } +#else + if (m_s.m_ext) { + m_ext = m_s.m_ext->copy(this); + } +#endif propagate(); m_qhead = m_trail.size(); TRACE("sat", m_s.display(tout); display(tout);); diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index 6ff228427..ce98bcce3 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -233,6 +233,7 @@ namespace sat { stats m_stats; model m_model; cube_state m_cube_state; + scoped_ptr m_ext; // --------------------------------------- // truth values @@ -605,6 +606,8 @@ namespace sat { double literal_occs(literal l); double literal_big_occs(literal l); + + sat::config const& get_config() const { return m_s.get_config(); } }; } From 5afef07f40cf80fb617aaab3bcf9215decd8e935 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 08:37:49 -0700 Subject: [PATCH 66/67] remove traces of old n-ary representation, add checks Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 333 ++++---------------------------------- src/sat/sat_lookahead.h | 21 +-- 2 files changed, 38 insertions(+), 316 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 11c946fba..1c3e9931c 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -270,6 +270,7 @@ namespace sat { sift_down(0, i); } } + SASSERT(validate_heap_sort()); } void lookahead::heapify() { @@ -293,6 +294,17 @@ namespace sat { if (i > j) m_candidates[i] = c; } + /** + * \brief validate that the result of heap sort sorts the candidates + * in descending order of their rating. + */ + bool lookahead::validate_heap_sort() { + for (unsigned i = 0; i + 1 < m_candidates.size(); ++i) + if (m_candidates[i].m_rating < m_candidates[i + 1].m_rating) + return false; + return true; + } + double lookahead::init_candidates(unsigned level, bool newbies) { m_candidates.reset(); double sum = 0; @@ -324,26 +336,6 @@ namespace sat { bool lookahead::is_unsat() const { // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. -#if OLD_NARY - bool all_false = true; - bool first = true; - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // skip the first entry, the length indicator. - first = false; - } - else if (l == null_literal) { - // when reaching the end of a clause check if all entries are false - if (all_false) return true; - all_false = true; - first = true; - } - else { - all_false &= is_false(l); - } - } -#else for (nary* n : m_nary_clauses) { bool all_false = true; for (literal l : *n) { @@ -351,7 +343,6 @@ namespace sat { } if (all_false) return true; } -#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -388,25 +379,6 @@ namespace sat { } // check if there is a clause whose literals are false. // every clause is terminated by a null-literal. -#if OLD_NARY - bool no_true = true; - bool first = true; - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // skip the first entry, the length indicator. - first = false; - } - else if (l == null_literal) { - if (no_true) return false; - no_true = true; - first = true; - } - else { - no_true &= !is_true(l); - } - } -#else for (nary * n : m_nary_clauses) { bool no_true = true; for (literal l : *n) { @@ -414,7 +386,6 @@ namespace sat { } if (no_true) return false; } -#endif // check if there is a ternary whose literals are false. for (unsigned idx = 0; idx < m_ternary.size(); ++idx) { literal lit = to_literal(idx); @@ -490,23 +461,17 @@ namespace sat { sum += (literal_occs(b.m_u) + literal_occs(b.m_v)) / 8.0; } sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { + for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; - literal lit; - unsigned j = idx; double to_add = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { + for (literal lit : *n) { if (!is_fixed(lit) && lit != ~l) { to_add += literal_occs(lit); } } - unsigned len = m_nary_literals[idx]; + unsigned len = n->size(); sum += pow(0.5, len) * to_add / len; } -#else - -#endif return sum; } @@ -525,17 +490,10 @@ namespace sat { } sum += 0.25 * m_ternary_count[(~l).index()]; unsigned sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned cls_idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - sum += pow(0.5, m_nary_literals[cls_idx]); - } -#else for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; sum += pow(0.5, n->size()); } -#endif return sum; } @@ -926,13 +884,8 @@ namespace sat { m_ternary.push_back(svector()); m_ternary_count.push_back(0); m_ternary_count.push_back(0); -#if OLD_NARY - m_nary.push_back(unsigned_vector()); - m_nary.push_back(unsigned_vector()); -#else m_nary.push_back(ptr_vector()); m_nary.push_back(ptr_vector()); -#endif m_nary_count.push_back(0); m_nary_count.push_back(0); m_bstamp.push_back(0); @@ -988,21 +941,9 @@ namespace sat { } } -#if 0 - // copy externals: - for (unsigned idx = 0; idx < m_s.m_watches.size(); ++idx) { - watch_list const& wl = m_s.m_watches[idx]; - for (watched const& w : wl) { - if (w.is_ext_constraint()) { - m_watches[idx].push_back(w); - } - } - } -#else if (m_s.m_ext) { m_ext = m_s.m_ext->copy(this); } -#endif propagate(); m_qhead = m_trail.size(); TRACE("sat", m_s.display(tout); display(tout);); @@ -1304,8 +1245,6 @@ namespace sat { watch_list::iterator it = wlist.begin(), it2 = it, end = wlist.end(); for (; it != end && !inconsistent(); ++it) { SASSERT(it->get_kind() == watched::EXT_CONSTRAINT); - VERIFY(is_true(l)); - VERIFY(!is_undef(l)); bool keep = m_s.m_ext->propagate(l, it->get_ext_constraint_idx()); if (m_search_mode == lookahead_mode::lookahead1 && !m_inconsistent) { lookahead_literal_occs_fun literal_occs_fn(*this); @@ -1330,26 +1269,13 @@ namespace sat { void lookahead::add_clause(clause const& c) { SASSERT(c.size() > 3); - -#if OLD_NARY - unsigned sz = c.size(); - unsigned idx = m_nary_literals.size(); - m_nary_literals.push_back(sz); - for (literal l : c) { - m_nary_literals.push_back(l.index()); - m_nary_count[l.index()]++; - m_nary[l.index()].push_back(idx); - SASSERT(m_nary_count[l.index()] == m_nary[l.index()].size()); - } - m_nary_literals.push_back(null_literal.index()); -#else void * mem = m_allocator.allocate(nary::get_obj_size(c.size())); nary * n = new (mem) nary(c.size(), c.begin()); m_nary_clauses.push_back(n); for (literal l : c) { m_nary[l.index()].push_back(n); + m_nary_count[l.index()]++; } -#endif } @@ -1359,57 +1285,6 @@ namespace sat { literal lit; SASSERT(m_search_mode == lookahead_mode::searching); -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - unsigned len = --m_nary_literals[idx]; - if (m_inconsistent) continue; - if (len <= 1) continue; // already processed - // find the two unassigned literals, if any - if (len == 2) { - literal l1 = null_literal; - literal l2 = null_literal; - unsigned j = idx; - bool found_true = false; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - if (l1 == null_literal) { - l1 = lit; - } - else { - SASSERT(l2 == null_literal); - l2 = lit; - break; - } - } - else if (is_true(lit)) { - // can't swap with idx. std::swap(m_nary_literals[j], m_nary_literals[idx]); - found_true = true; - break; - } - } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' - } - else if (l1 == null_literal) { - set_conflict(); - } - else if (l2 == null_literal) { - // clause may get revisited during propagation, when l2 is true in this clause. - // m_removed_clauses.push_back(std::make_pair(~l, idx)); - // remove_clause_at(~l, idx); - propagated(l1); - } - else { - // extract binary clause. A unary or empty clause may get revisited, - // but we skip it then because it is already handled as a binary clause. - // m_removed_clauses.push_back(std::make_pair(~l, idx)); // need to restore this clause. - // remove_clause_at(~l, idx); - try_add_binary(l1, l2); - } - } - } -#else for (nary * n : m_nary[(~l).index()]) { if (sz-- == 0) break; unsigned len = n->dec_size(); @@ -1458,20 +1333,12 @@ namespace sat { } } } -#endif // clauses where l is positive: sz = m_nary_count[l.index()]; -#if OLD_NARY - for (unsigned idx : m_nary[l.index()]) { - if (sz-- == 0) break; - remove_clause_at(l, idx); - } -#else for (nary* n : m_nary[l.index()]) { if (sz-- == 0) break; remove_clause_at(l, *n); } -#endif } void lookahead::propagate_clauses_lookahead(literal l) { @@ -1481,77 +1348,6 @@ namespace sat { SASSERT(m_search_mode == lookahead_mode::lookahead1 || m_search_mode == lookahead_mode::lookahead2); -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - literal l1 = null_literal; - literal l2 = null_literal; - unsigned j = idx; - bool found_true = false; - unsigned nonfixed = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - ++nonfixed; - if (l1 == null_literal) { - l1 = lit; - } - else if (l2 == null_literal) { - l2 = lit; - } - } - else if (is_true(lit)) { - found_true = true; - break; - } - } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' - } - else if (l1 == null_literal) { - set_conflict(); - return; - } - else if (l2 == null_literal) { - propagated(l1); - } - else if (m_search_mode == lookahead_mode::lookahead2) { - continue; - } - else { - SASSERT(nonfixed >= 2); - SASSERT(m_search_mode == lookahead_mode::lookahead1); - switch (m_config.m_reward_type) { - case heule_schur_reward: { - j = idx; - double to_add = 0; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (!is_fixed(lit)) { - to_add += literal_occs(lit); - } - } - m_lookahead_reward += pow(0.5, nonfixed) * to_add / nonfixed; - break; - } - case heule_unit_reward: - m_lookahead_reward += pow(0.5, nonfixed); - break; - case march_cu_reward: - m_lookahead_reward += 3.3 * pow(0.5, nonfixed - 2); - break; - case ternary_reward: - if (nonfixed == 2) { - m_lookahead_reward += (*m_heur)[l1.index()] * (*m_heur)[l2.index()]; - } - else { - m_lookahead_reward += (double)0.001; - } - break; - case unit_literal_reward: - break; - } - } - } -#else for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; literal l1 = null_literal; @@ -1616,34 +1412,8 @@ namespace sat { } } } -#endif } -#if OLD_NARY - void lookahead::remove_clause_at(literal l, unsigned clause_idx) { - unsigned j = clause_idx; - literal lit; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (lit != l) { - remove_clause(lit, clause_idx); - } - } - } - - void lookahead::remove_clause(literal l, unsigned clause_idx) { - unsigned_vector& pclauses = m_nary[l.index()]; - unsigned sz = m_nary_count[l.index()]--; - for (unsigned i = sz; i > 0; ) { - --i; - if (clause_idx == pclauses[i]) { - std::swap(pclauses[i], pclauses[sz-1]); - return; - } - } - UNREACHABLE(); - } -#else - void lookahead::remove_clause_at(literal l, nary& n) { for (literal lit : n) { if (lit != l) { @@ -1664,41 +1434,19 @@ namespace sat { } UNREACHABLE(); } -#endif void lookahead::restore_clauses(literal l) { SASSERT(m_search_mode == lookahead_mode::searching); // increase the length of clauses where l is negative unsigned sz = m_nary_count[(~l).index()]; -#if OLD_NARY - for (unsigned idx : m_nary[(~l).index()]) { - if (sz-- == 0) break; - ++m_nary_literals[idx]; - } -#else for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; n->inc_size(); } -#endif // add idx back to clause list where l is positive // add them back in the same order as they were inserted // in this way we can check that the clauses are the same. sz = m_nary_count[l.index()]; -#if OLD_NARY - unsigned_vector const& pclauses = m_nary[l.index()]; - for (unsigned i = sz; i > 0; ) { - --i; - unsigned j = pclauses[i]; - literal lit; - while ((lit = to_literal(m_nary_literals[++j])) != null_literal) { - if (lit != l) { - // SASSERT(m_nary[lit.index()] == pclauses[i]); - m_nary_count[lit.index()]++; - } - } - } -#else ptr_vector& pclauses = m_nary[l.index()]; for (unsigned i = sz; i-- > 0; ) { for (literal lit : *pclauses[i]) { @@ -1708,12 +1456,10 @@ namespace sat { } } } -#endif } void lookahead::propagate_clauses(literal l) { - VERIFY(is_true(l)); - VERIFY(value(l) == l_true); + SASSERT(is_true(l)); propagate_ternary(l); switch (m_search_mode) { case lookahead_mode::searching: @@ -1723,13 +1469,8 @@ namespace sat { propagate_clauses_lookahead(l); break; } - VERIFY(!is_undef(l)); - VERIFY(is_true(l)); - VERIFY(value(l) == l_true); propagate_external(l); - } - - + } void lookahead::update_binary_clause_reward(literal l1, literal l2) { SASSERT(!is_false(l1)); @@ -1829,6 +1570,8 @@ namespace sat { TRACE("sat_verbose", display(tout << scope_lvl() << " " << (inconsistent()?"unsat":"sat") << "\n");); } +#define CHECK_FAILED_LITERAL 0 + void lookahead::compute_lookahead_reward() { init_lookahead_reward(); TRACE("sat", display_lookahead(tout); ); @@ -1836,6 +1579,10 @@ namespace sat { unsigned base = 2; bool change = true; literal last_changed = null_literal; +#if CHECK_FAILED_LITERAL + unsigned_vector assigns; + literal_vector assigns_lits; +#endif while (change && !inconsistent()) { change = false; for (unsigned i = 0; !inconsistent() && i < m_lookahead.size(); ++i) { @@ -1863,6 +1610,10 @@ namespace sat { if (unsat) { TRACE("sat", tout << "backtracking and settting " << ~lit << "\n";); reset_lookahead_reward(); +#if CHECK_FAILED_LITERAL + assigns.push_back(m_trail.size()); + assigns_lits.push_back(~lit); +#endif assign(~lit); propagate(); init_lookahead_reward(); @@ -1882,6 +1633,12 @@ namespace sat { base += 2 * m_lookahead.size(); } reset_lookahead_reward(); +#if CHECK_FAILED_LITERAL + for (unsigned i = 0; i < assigns.size(); ++i) { + std::cout << "check trail: " << m_trail[assigns[i]] << " " << assigns_lits[i] << "\n"; + VERIFY(m_trail[assigns[i]] == assigns_lits[i]); + } +#endif TRACE("sat", display_lookahead(tout); ); } @@ -1892,8 +1649,6 @@ namespace sat { } void lookahead::reset_lookahead_reward() { - SASSERT(m_search_mode == lookahead_mode::lookahead1 || - m_search_mode == lookahead_mode::lookahead2); m_qhead = m_qhead_lim.back(); TRACE("sat", tout << "reset_lookahead_reward: " << m_qhead << "\n";); unsigned old_sz = m_trail_lim.back(); @@ -2317,28 +2072,10 @@ namespace sat { } } -#if OLD_NARY - for (unsigned l_idx : m_nary_literals) { - literal l = to_literal(l_idx); - if (first) { - // the first entry is a length indicator of non-false literals. - out << l_idx << ": "; - first = false; - } - else if (l == null_literal) { - first = true; - out << "\n"; - } - else { - out << l << " "; - } - } -#else for (nary * n : m_nary_clauses) { for (literal l : *n) out << l << " "; out << "\n"; } -#endif return out; } @@ -2432,7 +2169,7 @@ namespace sat { \brief simplify set of clauses by extracting units from a lookahead at base level. */ void lookahead::simplify() { - scoped_ext _scoped_ext(*this); + scoped_ext _scoped_ext(*this); SASSERT(m_prefix == 0); SASSERT(m_watches.empty()); m_search_mode = lookahead_mode::searching; diff --git a/src/sat/sat_lookahead.h b/src/sat/sat_lookahead.h index ce98bcce3..e60924425 100644 --- a/src/sat/sat_lookahead.h +++ b/src/sat/sat_lookahead.h @@ -20,7 +20,7 @@ Notes: #ifndef _SAT_LOOKAHEAD_H_ #define _SAT_LOOKAHEAD_H_ -#define OLD_NARY 0 +// #define OLD_NARY 0 #include "sat_elim_eqs.h" @@ -194,16 +194,9 @@ namespace sat { vector> m_ternary; // lit |-> vector of ternary clauses unsigned_vector m_ternary_count; // lit |-> current number of active ternary clauses for lit -#if OLD_NARY - vector m_nary; // lit |-> vector of clause_id - unsigned_vector m_nary_literals; // the actual literals, clauses start at offset clause_id, - // the first entry is the current length, clauses are separated by a null_literal - -#else small_object_allocator m_allocator; vector> m_nary; // lit |-> vector of nary clauses ptr_vector m_nary_clauses; // vector of all nary clauses -#endif unsigned_vector m_nary_count; // lit |-> number of valid clause_id in m_nary[lit] unsigned m_num_tc1; @@ -331,10 +324,10 @@ namespace sat { double get_rating(bool_var v) const { return m_rating[v]; } double get_rating(literal l) const { return get_rating(l.var()); } bool select(unsigned level); - //void sift_up(unsigned j); void heap_sort(); - void heapify(); + void heapify(); void sift_down(unsigned j, unsigned sz); + bool validate_heap_sort(); double init_candidates(unsigned level, bool newbies); std::ostream& display_candidates(std::ostream& out) const; bool is_unsat() const; @@ -457,13 +450,8 @@ namespace sat { void propagate_clauses_searching(literal l); void propagate_clauses_lookahead(literal l); void restore_clauses(literal l); -#if OLD_NARY - void remove_clause(literal l, unsigned clause_idx); - void remove_clause_at(literal l, unsigned clause_idx); -#else void remove_clause(literal l, nary& n); void remove_clause_at(literal l, nary& n); -#endif // ------------------------------------ // initialization @@ -552,12 +540,9 @@ namespace sat { ~lookahead() { m_s.rlimit().pop_child(); -#if OLD_NARY -#else for (nary* n : m_nary_clauses) { m_allocator.deallocate(n->obj_size(), n); } -#endif } From 4adf4d4ac2238ac2dbd9a69547c2979f6b8ce9c8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Oct 2017 12:08:54 -0700 Subject: [PATCH 67/67] micro opt Signed-off-by: Nikolaj Bjorner --- src/sat/sat_lookahead.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/sat/sat_lookahead.cpp b/src/sat/sat_lookahead.cpp index 1c3e9931c..ed5976838 100644 --- a/src/sat/sat_lookahead.cpp +++ b/src/sat/sat_lookahead.cpp @@ -112,7 +112,6 @@ namespace sat { } } - void lookahead::inc_bstamp() { ++m_bstamp_id; if (m_bstamp_id == 0) { @@ -120,6 +119,7 @@ namespace sat { m_bstamp.fill(0); } } + void lookahead::inc_istamp() { ++m_istamp_id; if (m_istamp_id == 0) { @@ -1350,9 +1350,13 @@ namespace sat { for (nary* n : m_nary[(~l).index()]) { if (sz-- == 0) break; + + if (is_true(n->get_head())) { + continue; + } literal l1 = null_literal; literal l2 = null_literal; - bool found_true = false; + bool skip_clause = false; unsigned nonfixed = 0; for (literal lit : *n) { if (!is_fixed(lit)) { @@ -1363,14 +1367,19 @@ namespace sat { else if (l2 == null_literal) { l2 = lit; } + else if (m_search_mode == lookahead_mode::lookahead2) { + skip_clause = true; + break; + } } else if (is_true(lit)) { - found_true = true; + n->set_head(lit); + skip_clause = true; break; } } - if (found_true) { - // skip, the clause will be removed when propagating on 'lit' + if (skip_clause) { + // skip, the clause } else if (l1 == null_literal) { set_conflict(); @@ -1379,9 +1388,6 @@ namespace sat { else if (l2 == null_literal) { propagated(l1); } - else if (m_search_mode == lookahead_mode::lookahead2) { - continue; - } else { SASSERT(nonfixed >= 2); SASSERT(m_search_mode == lookahead_mode::lookahead1);