From 1d9aad6ea9df35e939e34558b43a5a24eb823e19 Mon Sep 17 00:00:00 2001 From: Margus Veanes Date: Mon, 20 Dec 2021 17:44:06 -0800 Subject: [PATCH 01/88] improved regex merging avoiding unsat nontermination (#5728) --- src/ast/rewriter/seq_rewriter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index aeda76da5..40a46ec0f 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3331,7 +3331,7 @@ expr_ref seq_rewriter::mk_regex_union_normalize(expr* r1, expr* r2) { SASSERT(m_util.is_re(r2)); expr_ref result(m()); std::function test = [&](expr* t, expr*& a, expr*& b) { return re().is_union(t, a, b); }; - std::function compose = [&](expr* r1, expr* r2) { return re().mk_union(r1, r2); }; + std::function compose = [&](expr* r1, expr* r2) { return (is_subset(r1, r2) ? r2 : (is_subset(r2, r1) ? r1 : re().mk_union(r1, r2))); }; if (r1 == r2 || re().is_empty(r2) || re().is_full_seq(r1)) result = r1; else if (re().is_empty(r1) || re().is_full_seq(r2)) @@ -3353,7 +3353,7 @@ expr_ref seq_rewriter::mk_regex_inter_normalize(expr* r1, expr* r2) { if (re().is_epsilon(r2)) std::swap(r1, r2); std::function test = [&](expr* t, expr*& a, expr*& b) { return re().is_intersection(t, a, b); }; - std::function compose = [&](expr* r1, expr* r2) { return re().mk_inter(r1, r2); }; + std::function compose = [&](expr* r1, expr* r2) { return (is_subset(r1, r2) ? r1 : (is_subset(r2, r1) ? r2 : re().mk_inter(r1, r2))); }; if (r1 == r2 || re().is_empty(r1) || re().is_full_seq(r2)) result = r1; else if (re().is_empty(r2) || re().is_full_seq(r1)) @@ -4598,6 +4598,8 @@ bool seq_rewriter::is_subset(expr* r1, expr* r2) const { return true; if (re().is_full_seq(r2)) return true; + if (re().is_dot_plus(r2) && re().get_info(r1).nullable == l_false) + return true; if (is_concat(r1, ra1, ra2, ra3) && is_concat(r2, rb1, rb2, rb3) && ra1 == rb1 && ra2 == rb2) { r1 = ra3; From 94a2c91f397c2c155fdedf1c1cc75b6532f62e5f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 21 Dec 2021 18:30:22 +0000 Subject: [PATCH 02/88] fix a few compiler warnings --- src/tactic/user_propagator_base.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/tactic/user_propagator_base.h b/src/tactic/user_propagator_base.h index 534b9dbc0..403df8af5 100644 --- a/src/tactic/user_propagator_base.h +++ b/src/tactic/user_propagator_base.h @@ -14,7 +14,7 @@ namespace user_propagator { class context_obj { public: - virtual ~context_obj() {} + virtual ~context_obj() = default; }; typedef std::function final_eh_t; @@ -33,11 +33,7 @@ namespace user_propagator { enum kind_t { OP_USER_PROPAGATE }; - virtual ~plugin() {} - - virtual decl_plugin* mk_fresh() { return alloc(plugin); } - - family_id get_family_id() const { return m_family_id; } + decl_plugin* mk_fresh() override { return alloc(plugin); } sort* mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) override { UNREACHABLE(); @@ -45,7 +41,7 @@ namespace user_propagator { } func_decl* mk_func_decl(decl_kind k, unsigned num_parameters, parameter const* parameters, - unsigned arity, sort* const* domain, sort* range) { + unsigned arity, sort* const* domain, sort* range) override { UNREACHABLE(); return nullptr; } From 9d82c1d8a9a350341ba2f0a00bbc3f3f201c5ae9 Mon Sep 17 00:00:00 2001 From: zhouzhenghui Date: Wed, 22 Dec 2021 02:47:13 +0800 Subject: [PATCH 03/88] fix deadlock in scoped_timer destructor (#5371) --- src/util/scoped_timer.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index e144cf636..a36e762aa 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -33,12 +33,14 @@ Revision History: #include #endif +enum scoped_timer_work_state { IDLE = 0, WORKING = 1, EXITING = 2 }; + struct scoped_timer_state { std::thread m_thread; std::timed_mutex m_mutex; event_handler * eh; unsigned ms; - std::atomic work; + std::atomic work; std::condition_variable_any cv; }; @@ -49,11 +51,11 @@ static atomic num_workers(0); static void thread_func(scoped_timer_state *s) { workers.lock(); while (true) { - s->cv.wait(workers, [=]{ return s->work > 0; }); + s->cv.wait(workers, [=]{ return s->work > IDLE; }); workers.unlock(); // exiting.. - if (s->work == 2) + if (s->work == EXITING) return; auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(s->ms); @@ -68,9 +70,8 @@ static void thread_func(scoped_timer_state *s) { s->m_mutex.unlock(); next: - s->work = 0; + s->work = IDLE; workers.lock(); - available_workers.push_back(s); } } @@ -97,7 +98,7 @@ public: s->ms = ms; s->eh = eh; s->m_mutex.lock(); - s->work = 1; + s->work = WORKING; if (new_worker) { s->m_thread = std::thread(thread_func, s); } @@ -108,8 +109,11 @@ public: ~imp() { s->m_mutex.unlock(); - while (s->work == 1) + while (s->work == WORKING) std::this_thread::yield(); + workers.lock(); + available_workers.push_back(s); + workers.unlock(); } }; @@ -139,7 +143,7 @@ void scoped_timer::finalize() { while (deleted < num_workers) { workers.lock(); for (auto w : available_workers) { - w->work = 2; + w->work = EXITING; w->cv.notify_one(); } decltype(available_workers) cleanup_workers; From 09ee60ccced6c419dee472b31ce75317a83485de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 19 Dec 2021 18:08:16 -0800 Subject: [PATCH 04/88] update comment Signed-off-by: Nikolaj Bjorner --- src/smt/smt_kernel.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 5c28d52fd..681bdd55b 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -307,13 +307,13 @@ namespace smt { /** \brief Return a reference to smt::context. - This is a temporary hack to support user theories. - TODO: remove this hack. - We need to revamp user theories too. + This breaks abstractions. + + It is currently used by the opt-solver + to access optimization services from arithmetic solvers + and to ensure that the solver has registered PB theory solver. - This method breaks the abstraction barrier. - - \warning We should not use this method + \warning This method should not be used in new code. */ context & get_context(); }; From 4b5ee91b442d2f22d410c6c0fedb802ab0519013 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 21 Dec 2021 20:40:58 -0800 Subject: [PATCH 05/88] na Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.h | 7 +-- src/sat/smt/euf_relevancy.cpp | 93 ++++++++++++++++++++++++++++------- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/euf_solver.h | 10 ++-- 4 files changed, 88 insertions(+), 24 deletions(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b6affe4ee..c4e38fb06 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -444,9 +444,10 @@ namespace sat { void flush_roots(); typedef std::pair bin_clause; struct bin_clause_hash { unsigned operator()(bin_clause const& b) const { return b.first.hash() + 2*b.second.hash(); } }; - protected: - watch_list & get_wlist(literal l) { return m_watches[l.index()]; } - watch_list const & get_wlist(literal l) const { return m_watches[l.index()]; } + + watch_list const& get_wlist(literal l) const { return m_watches[l.index()]; } + watch_list& get_wlist(literal l) { return m_watches[l.index()]; } + protected: watch_list & get_wlist(unsigned l_idx) { return m_watches[l_idx]; } bool is_marked(bool_var v) const { return m_mark[v]; } void mark(bool_var v) { SASSERT(!is_marked(v)); m_mark[v] = true; } diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 40dff962a..50804e538 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -89,7 +89,7 @@ namespace euf { m_dual_solver->track_relevancy(v); } - bool solver::init_relevancy() { + bool solver::init_relevancy1() { m_relevant_expr_ids.reset(); if (!relevancy_enabled()) return true; @@ -97,31 +97,91 @@ namespace euf { return true; if (!(*m_dual_solver)(s())) return false; + init_relevant_expr_ids(); + + for (auto lit : m_dual_solver->core()) + push_relevant(lit.var()); + + relevant_subterms(); + + return true; + } + + void solver::push_relevant(sat::bool_var v) { + expr* e = m_bool_var2expr.get(v, nullptr); + if (e) + m_relevant_todo.push_back(e); + } + + + bool solver::init_relevancy2() { + m_relevant_expr_ids.reset(); + if (!relevancy_enabled()) + return true; + init_relevant_expr_ids(); + for (unsigned i = 0; i < s().trail_size(); ++i) { + sat::literal l = s().trail_literal(i); + auto v = l.var(); + auto j = s().get_justification(v); + switch (j.get_kind()) { + case sat::justification::kind::BINARY: + case sat::justification::kind::TERNARY: + case sat::justification::kind::CLAUSE: + case sat::justification::kind::EXT_JUSTIFICATION: + push_relevant(l.var()); + break; + case sat::justification::kind::NONE: + for (auto const& w : s().get_wlist(~l)) { + if (w.is_binary_non_learned_clause()) { + if (is_propagated(w.get_literal())) + continue; + } + else if (w.is_binary_clause()) + continue; + else if (w.is_ternary_clause()) { + if (is_propagated(w.get_literal1())) + continue; + if (is_propagated(w.get_literal2())) + continue; + } + else if (w.is_clause()) { + if (is_propagated(w.get_blocked_literal())) + continue; + } + push_relevant(l.var()); + break; + } + break; + } + } + relevant_subterms(); + return true; + } + + bool solver::is_propagated(sat::literal lit) { + return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none(); + } + + void solver::init_relevant_expr_ids() { unsigned max_id = 0; for (enode* n : m_egraph.nodes()) max_id = std::max(max_id, n->get_expr_id()); m_relevant_expr_ids.resize(max_id + 1, false); + m_relevant_todo.reset(); + m_relevant_todo.append(m_auto_relevant); + } + + void solver::relevant_subterms() { ptr_vector& todo = m_relevant_todo; bool_vector& visited = m_relevant_visited; - auto const& core = m_dual_solver->core(); - todo.reset(); - for (auto lit : core) { - expr* e = m_bool_var2expr.get(lit.var(), nullptr); - if (e) - todo.push_back(e); - } -#if 0 - std::cout << "init-relevant\n"; - for (expr* e : m_auto_relevant) - std::cout << "auto-relevant " << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; -#endif - todo.append(m_auto_relevant); for (unsigned i = 0; i < todo.size(); ++i) { expr* e = todo[i]; if (visited.get(e->get_id(), false)) continue; visited.setx(e->get_id(), true, false); - if (!si.is_bool_op(e)) + if (si.is_bool_op(e)) + continue; + else m_relevant_expr_ids.setx(e->get_id(), true, false); if (!is_app(e)) continue; @@ -152,8 +212,7 @@ namespace euf { TRACE("euf", for (enode* n : m_egraph.nodes()) - if (is_relevant(n)) + if (is_relevant(n)) tout << "relevant " << n->get_expr_id() << " [r" << n->get_root_id() << "]: " << mk_bounded_pp(n->get_expr(), m) << "\n";); - return true; } } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index bbdd6ce0e..1de9a0b0f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -459,7 +459,7 @@ namespace euf { if (unit_propagate()) return sat::check_result::CR_CONTINUE; - if (!init_relevancy()) + if (!init_relevancy1()) give_up = true; unsigned num_nodes = m_egraph.num_nodes(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 384e15822..8eef21bac 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -185,13 +185,17 @@ namespace euf { bool_vector m_relevant_visited; ptr_vector m_relevant_todo; void ensure_dual_solver(); - bool init_relevancy(); - - + bool init_relevancy1(); + bool init_relevancy2(); + void relevant_subterms(); + void init_relevant_expr_ids(); + void push_relevant(sat::bool_var v); + bool is_propagated(sat::literal lit); // invariant void check_eqc_bool_assignment() const; void check_missing_bool_enode_propagation() const; void check_missing_eq_propagation() const; + // diagnosis std::ostream& display_justification_ptr(std::ostream& out, size_t* j) const; From cf6486f990dfa638977bfcd17d6cffd2c735ad34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Dec 2021 07:43:37 -0800 Subject: [PATCH 06/88] bug in flatten/and/or introduced when skipping sub-expressions Signed-off-by: Nikolaj Bjorner --- src/ast/ast_util.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 69b63af0f..090a2ff9d 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -264,8 +264,12 @@ void flatten_and(expr_ref_vector& result) { expr_fast_mark1 seen; for (unsigned i = 0; i < result.size(); ++i) { expr* e = result.get(i); - if (seen.is_marked(e)) + if (seen.is_marked(e)) { + result[i] = result.back(); + result.pop_back(); + --i; continue; + } seen.mark(e); pin.push_back(e); if (m.is_and(e)) { @@ -330,8 +334,12 @@ void flatten_or(expr_ref_vector& result) { expr_fast_mark1 seen; for (unsigned i = 0; i < result.size(); ++i) { expr* e = result.get(i); - if (seen.is_marked(e)) + if (seen.is_marked(e)) { + result[i] = result.back(); + result.pop_back(); + --i; continue; + } seen.mark(e); pin.push_back(e); if (m.is_or(e)) { From f3af2193d0f20ea5d6a3d727c5c97f0255aec3a4 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Dec 2021 23:53:47 +0800 Subject: [PATCH 07/88] Use Stdlib. instead of Pervasives. due to deprecation (#5730) --- src/api/ml/z3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 1448a9ea5..b904937a9 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -203,7 +203,7 @@ end = struct let equal = (=) (* The standard comparison uses the custom operations of the C layer *) - let compare = Pervasives.compare + let compare = Stdlib.compare let translate (x:ast) (to_ctx:context) = if gc x = to_ctx then From 78222f274cfdc5a1194e02172b1cee45a3196b0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Dec 2021 07:55:59 -0800 Subject: [PATCH 08/88] remove action that fails too often --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ea894a93a..f6753c09b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -312,7 +312,7 @@ jobs: make -j3 _ex_ml_example_post_install ./ml_example_shared.byte ./ml_example_shared_custom.byte - ./ml_example_shared + # ./ml_example_shared cd .. # Skip as dead-slow in debug mode: # - template: scripts/test-z3.yml From f11fcec082e92d350eaa5b0aaad2180711622bc2 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Dec 2021 23:59:13 +0800 Subject: [PATCH 09/88] Migrate from deprecated `distutils.sysconfig` in scripts (#5729) --- scripts/mk_util.py | 8 ++++---- src/api/python/CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e6d34dc3e..b73e1b329 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -15,7 +15,7 @@ import shutil from mk_exception import * import mk_genfile_common from fnmatch import fnmatch -import distutils.sysconfig +import sysconfig import compileall import subprocess @@ -48,7 +48,7 @@ CXX_COMPILERS=['g++', 'clang++'] C_COMPILERS=['gcc', 'clang'] JAVAC=None JAR=None -PYTHON_PACKAGE_DIR=distutils.sysconfig.get_python_lib(prefix=getenv("PREFIX", None)) +PYTHON_PACKAGE_DIR=sysconfig.get_path('purelib') BUILD_DIR='build' REV_BUILD_DIR='..' SRC_DIR='src' @@ -1611,7 +1611,7 @@ class PythonInstallComponent(Component): os.path.join(self.pythonPkgDir,'z3'), in_prefix=self.in_prefix_install) - if PYTHON_PACKAGE_DIR != distutils.sysconfig.get_python_lib(): + if PYTHON_PACKAGE_DIR != sysconfig.get_path('purelib'): out.write('\t@echo Z3Py was installed at \'%s\', make sure this directory is in your PYTHONPATH environment variable.' % PYTHON_PACKAGE_DIR) def mk_uninstall(self, out): @@ -2692,7 +2692,7 @@ def mk_config(): print("Python pkg dir: %s" % PYTHON_PACKAGE_DIR) if GPROF: print('gprof: enabled') - print('Python version: %s' % distutils.sysconfig.get_python_version()) + print('Python version: %s' % sysconfig.get_python_version()) if is_java_enabled(): print('JNI Bindings: %s' % JNI_HOME) print('Java Compiler: %s' % JAVAC) diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt index 8e50ad255..e791a2f11 100644 --- a/src/api/python/CMakeLists.txt +++ b/src/api/python/CMakeLists.txt @@ -99,7 +99,7 @@ if (Z3_INSTALL_PYTHON_BINDINGS) message(STATUS "CMAKE_INSTALL_PYTHON_PKG_DIR not set. Trying to guess") execute_process( COMMAND "${PYTHON_EXECUTABLE}" "-c" - "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())" + "import sysconfig; print(sysconfig.get_path('purelib'))" RESULT_VARIABLE exit_code OUTPUT_VARIABLE CMAKE_INSTALL_PYTHON_PKG_DIR OUTPUT_STRIP_TRAILING_WHITESPACE From 4d8bf2a874e34f91b7974e9b8d7256ebf804b55b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Dec 2021 13:14:06 -0800 Subject: [PATCH 10/88] wrong unit for xor in aig tactic #5722 --- src/tactic/aig/aig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 37027e63a..b689a53e2 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -559,7 +559,7 @@ struct aig_manager::imp { aig_lit r; switch (num) { case 0: - r = m.m_true; + r = m.m_false; break; case 1: r = m_result_stack[spos]; From 71b868d7f623afd0f77899121171bc6ef0dc4e1f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 22 Dec 2021 13:32:53 -0800 Subject: [PATCH 11/88] #5722 - internalize unary xnor --- src/sat/smt/bv_internalize.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 439764515..2fec734df 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -166,6 +166,7 @@ namespace bv { #define internalize_pun(F) pun = [&](unsigned sz, expr* const* xs, unsigned p, expr_ref_vector& bits) { m_bb.F(sz, xs, p, bits);}; internalize_par_unary(a, pun); #define internalize_nfl(F) ebin = [&](unsigned sz, expr* const* xs, expr* const* ys, expr_ref& out) { m_bb.F(sz, xs, ys, out);}; internalize_novfl(a, ebin); #define internalize_int(B, U) ibin = [&](expr* x, expr* y) { return B(x, y); }; iun = [&](expr* x) { return U(x); }; internalize_interp(a, ibin, iun); +#define if_unary(F) if (a->get_num_args() == 1) { internalize_un(F); break; } switch (a->get_decl_kind()) { case OP_BV_NUM: internalize_num(a); break; @@ -190,7 +191,7 @@ namespace bv { case OP_BXOR: internalize_ac(mk_xor); break; case OP_BNAND: internalize_bin(mk_nand); break; case OP_BNOR: internalize_bin(mk_nor); break; - case OP_BXNOR: internalize_bin(mk_xnor); break; + case OP_BXNOR: if_unary(mk_not); internalize_bin(mk_xnor); break; case OP_BCOMP: internalize_bin(mk_comp); break; case OP_SIGN_EXT: internalize_pun(mk_sign_extend); break; case OP_ZERO_EXT: internalize_pun(mk_zero_extend); break; From 5afb95b34aeab0a475d2c2f4512723fc2b386c25 Mon Sep 17 00:00:00 2001 From: Margus Veanes Date: Wed, 22 Dec 2021 17:53:34 -0800 Subject: [PATCH 12/88] improved subset checking for regexes with counters (#5731) --- src/ast/rewriter/seq_rewriter.cpp | 43 ++++++++++++++++++++++++++----- src/ast/rewriter/seq_rewriter.h | 1 + 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 40a46ec0f..c04c9991b 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3112,7 +3112,7 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref else // D(e,r1)r2|(ite (r1nullable) (D(e,r2)) []) // observe that (mk_ite_simplify(true, D(e,r2), []) = D(e,r2) - result = mk_regex_union_normalize(c1, re().mk_ite_simplify(r1nullable, mk_antimirov_deriv(e, r2, path), nothing())); + result = mk_antimirov_deriv_union(c1, re().mk_ite_simplify(r1nullable, mk_antimirov_deriv(e, r2, path), nothing())); } else if (m().is_ite(r, c, r1, r2)) { c1 = simplify_path(e, m().mk_and(c, path)); @@ -3171,7 +3171,7 @@ void seq_rewriter::mk_antimirov_deriv_rec(expr* e, expr* r, expr* path, expr_ref result = re().mk_ite_simplify(range, epsilon(), nothing()); } else if (re().is_union(r, r1, r2)) - result = mk_regex_union_normalize(mk_antimirov_deriv(e, r1, path), mk_antimirov_deriv(e, r2, path)); + result = mk_antimirov_deriv_union(mk_antimirov_deriv(e, r1, path), mk_antimirov_deriv(e, r2, path)); else if (re().is_intersection(r, r1, r2)) result = mk_antimirov_deriv_intersection(e, mk_antimirov_deriv(e, r1, path), @@ -3237,11 +3237,11 @@ expr_ref seq_rewriter::mk_antimirov_deriv_intersection(expr* e, expr* d1, expr* result = mk_antimirov_deriv_restrict(e, d2, path); else if (re().is_union(d1, a, b)) // distribute intersection over the union in d1 - result = mk_regex_union_normalize(mk_antimirov_deriv_intersection(e, a, d2, path), + result = mk_antimirov_deriv_union(mk_antimirov_deriv_intersection(e, a, d2, path), mk_antimirov_deriv_intersection(e, b, d2, path)); else if (re().is_union(d2, a, b)) // distribute intersection over the union in d2 - result = mk_regex_union_normalize(mk_antimirov_deriv_intersection(e, d1, a, path), + result = mk_antimirov_deriv_union(mk_antimirov_deriv_intersection(e, d1, a, path), mk_antimirov_deriv_intersection(e, d1, b, path)); else result = mk_regex_inter_normalize(d1, d2); @@ -3256,7 +3256,7 @@ expr_ref seq_rewriter::mk_antimirov_deriv_concat(expr* d, expr* r) { if (m().is_ite(d, c, t, e)) result = m().mk_ite(c, mk_antimirov_deriv_concat(t, r), mk_antimirov_deriv_concat(e, r)); else if (re().is_union(d, t, e)) - result = mk_regex_union_normalize(mk_antimirov_deriv_concat(t, r), mk_antimirov_deriv_concat(e, r)); + result = mk_antimirov_deriv_union(mk_antimirov_deriv_concat(t, r), mk_antimirov_deriv_concat(e, r)); else result = mk_re_append(d, r); return result; @@ -3284,7 +3284,7 @@ expr_ref seq_rewriter::mk_antimirov_deriv_negate(expr* elem, expr* d) { else if (re().is_union(d, t, e)) result = mk_antimirov_deriv_intersection(elem, mk_antimirov_deriv_negate(elem, t), mk_antimirov_deriv_negate(elem, e), m().mk_true()); else if (re().is_intersection(d, t, e)) - result = mk_regex_union_normalize(mk_antimirov_deriv_negate(elem, t), mk_antimirov_deriv_negate(elem, e)); + result = mk_antimirov_deriv_union(mk_antimirov_deriv_negate(elem, t), mk_antimirov_deriv_negate(elem, e)); else if (re().is_complement(d, t)) result = t; else @@ -3292,6 +3292,20 @@ expr_ref seq_rewriter::mk_antimirov_deriv_negate(expr* elem, expr* d) { return result; } +expr_ref seq_rewriter::mk_antimirov_deriv_union(expr* d1, expr* d2) { + sort* seq_sort = nullptr, * ele_sort = nullptr; + VERIFY(m_util.is_re(d1, seq_sort)); + VERIFY(m_util.is_seq(seq_sort, ele_sort)); + expr_ref result(m()); + expr* c1, * t1, * e1, * c2, * t2, * e2; + if (m().is_ite(d1, c1, t1, e1) && m().is_ite(d2, c2, t2, e2) && c1 == c2) + // eliminate duplicate branching on exactly the same condition + result = m().mk_ite(c1, mk_antimirov_deriv_union(t1, t2), mk_antimirov_deriv_union(e1, e2)); + else + result = mk_regex_union_normalize(d1, d2); + return result; +} + // restrict the guards of all conditionals id d and simplify the resulting derivative // restrict(if(c, a, b), cond) = if(c, restrict(a, cond & c), restrict(b, cond & ~c)) // restrict(a U b, cond) = restrict(a, cond) U restrict(b, cond) @@ -3320,7 +3334,7 @@ expr_ref seq_rewriter::mk_antimirov_deriv_restrict(expr* e, expr* d, expr* cond) else if (re().is_union(d, a, b)) { expr_ref a1(mk_antimirov_deriv_restrict(e, a, cond), m()); expr_ref b1(mk_antimirov_deriv_restrict(e, b, cond), m()); - result = mk_regex_union_normalize(a1, b1); + result = mk_antimirov_deriv_union(a1, b1); } return result; } @@ -4586,6 +4600,7 @@ bool seq_rewriter::is_subset(expr* r1, expr* r2) const { // return false; expr* ra1 = nullptr, *ra2 = nullptr, *ra3 = nullptr; expr* rb1 = nullptr, *rb2 = nullptr, *rb3 = nullptr; + unsigned la, ua, lb, ub; if (re().is_complement(r1, ra1) && re().is_complement(r2, rb1)) { return is_subset(rb1, ra1); @@ -4611,6 +4626,20 @@ bool seq_rewriter::is_subset(expr* r1, expr* r2) const { r1 = ra2; continue; } + // r1=ra3{la,ua}ra2, r2=rb3{lb,ub}rb2, ra3=rb3, lb<=la, ua<=ub + if (re().is_concat(r1, ra1, ra2) && re().is_loop(ra1, ra3, la, ua) && + re().is_concat(r2, rb1, rb2) && re().is_loop(rb1, rb3, lb, ub) && + ra3 == rb3 && lb <= la && ua <= ub) { + r1 = ra2; + r2 = rb2; + continue; + } + // ra1=ra3{la,ua}, r2=rb3{lb,ub}, ra3=rb3, lb<=la, ua<=ub + if (re().is_loop(r1, ra3, la, ua) && + re().is_loop(r2, rb3, lb, ub) && + ra3 == rb3 && lb <= la && ua <= ub) { + return true; + } return false; } } diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 9357a2be8..0d8ac029c 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -217,6 +217,7 @@ class seq_rewriter { expr_ref mk_antimirov_deriv_intersection(expr* elem, expr* d1, expr* d2, expr* path); expr_ref mk_antimirov_deriv_concat(expr* d, expr* r); expr_ref mk_antimirov_deriv_negate(expr* elem, expr* d); + expr_ref mk_antimirov_deriv_union(expr* d1, expr* d2); expr_ref mk_antimirov_deriv_restrict(expr* elem, expr* d1, expr* cond); expr_ref mk_regex_reverse(expr* r); expr_ref mk_regex_concat(expr* r1, expr* r2); From a00d68fe5af61eaa33030e76e24cc93bfd481a33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 11:43:38 -0800 Subject: [PATCH 13/88] update release scripts and notes in master Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 7 +++++++ scripts/release.yml | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 790691c3d..78cd70fb0 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -11,6 +11,13 @@ Version 4.8.next - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.8.14 +============== + - fixes Antimirov derivatives for intersections and unions required + required for solving non-emptiness constraints. + - includes x86 dll in nuget package for Windows. + - exposes additional user propagator functionality + Version 4.8.13 ============== The release integrates various bug fixes and tuning. diff --git a/scripts/release.yml b/scripts/release.yml index 78a58de59..fc026abb6 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.8.13' + ReleaseVersion: '4.8.14' stages: @@ -391,7 +391,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(0,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 5d4420a7635605698c073e8a7ac0efaab2adbf99 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 11:46:47 -0800 Subject: [PATCH 14/88] Update release.yml for Azure Pipelines --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index fc026abb6..69c26d624 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -313,7 +313,7 @@ stages: jobs: - job: GitHubPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to GitHub" pool: vmImage: "windows-latest" From bd2a53c4753aad171d362084bdbe92e0a79dc52e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 11:48:08 -0800 Subject: [PATCH 15/88] Update release.yml for Azure Pipelines --- scripts/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 69c26d624..7f297dcd2 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -167,10 +167,11 @@ stages: - powershell: write-host $(System.TeamProjectId) displayName: 'System.TeamProjectId' - task: DownloadPipelineArtifact@2 - displayName: 'Download Win64 Build' + displayName: 'Download NWin64 Build' inputs: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory)\package + - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: artifact: 'WindowsBuild-x86' From df8f9d7dcb8b9f9b3de1072017b7c2b7f63f0af8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 12:43:00 -0800 Subject: [PATCH 16/88] Update release.yml for Azure Pipelines --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 7f297dcd2..26049fac8 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -392,7 +392,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(0,1) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From dc09d3c5ea07532e85ead803fb5acd77f99bf48f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 11:50:45 -0800 Subject: [PATCH 17/88] fix typo Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 26049fac8..ce2abc9a4 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -167,7 +167,7 @@ stages: - powershell: write-host $(System.TeamProjectId) displayName: 'System.TeamProjectId' - task: DownloadPipelineArtifact@2 - displayName: 'Download NWin64 Build' + displayName: 'Download Win64 Build' inputs: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory)\package From ecf41972b1ddd07bf56ee76393ac69cc0865a3b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 14:41:43 -0800 Subject: [PATCH 18/88] increase minor version Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- docker/ubuntu-20-04.Dockerfile | 45 ++++++++++++++++++++++++++++++++++ scripts/mk_project.py | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 docker/ubuntu-20-04.Dockerfile diff --git a/CMakeLists.txt b/CMakeLists.txt index f1ad74181..be300607d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.4) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.8.14.0 LANGUAGES CXX) +project(Z3 VERSION 4.8.15.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/docker/ubuntu-20-04.Dockerfile b/docker/ubuntu-20-04.Dockerfile new file mode 100644 index 000000000..7f20b753f --- /dev/null +++ b/docker/ubuntu-20-04.Dockerfile @@ -0,0 +1,45 @@ +# ------------- +# OS Base image +# ------------- +# >> Includes system-wide dependencies +FROM ubuntu:20.04 as lib-base +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update && \ + apt-get -y --no-install-recommends install \ + cmake \ + make \ + clang \ + g++ \ + curl \ + default-jdk \ + python3 \ + python3-setuptools \ + python-is-python3 \ + sudo + +# ---------------- +# Z3 Builder Image +# ---------------- +# >> Includes build files and compiles the basic z3 sources +FROM lib-base as builder +COPY ./ /z3-source/ +WORKDIR /z3-source/ +RUN python scripts/mk_make.py +WORKDIR /z3-source/build/ +RUN make +RUN sudo make install +WORKDIR /z3-source/ + +# ------- +# Bare z3 +# ------- +# >> Includes only stnadard z3 installations. +# >> Can be used as a standalone interface to z3. +FROM builder as bare-z3 +ENTRYPOINT [ "z3" ] + +# TODO: introduce Python-binding stage +# ... + +# TODO(optional): introduce C/C++ -binding stage +# ... \ No newline at end of file diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 105c097d4..17a76060a 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 8, 14, 0) + set_version(4, 8, 15, 0) # Z3 Project definition def init_project_def(): From 6b0dc6d144c2f593429422c0bf12a6d3dd049673 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 23 Dec 2021 14:43:12 -0800 Subject: [PATCH 19/88] Create docker-image.yml thanks #5735 --- .github/workflows/docker-image.yml | 58 ++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/docker-image.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 000000000..fa02c0aec --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,58 @@ +name: Publish Docker image + +on: + schedule: + - cron: "0 1 * * 0" # every Sunday at 1 am + workflow_dispatch: # on button click + +jobs: + push_to_registry: + name: Push Docker image to Docker Hub + runs-on: ubuntu-latest + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + # ------- + # BARE Z3 + # ------- + - name: Extract metadata (tags, labels) for Bare Z3 Docker Image + id: meta + uses: docker/metadata-action@v3 + with: + images: deemetree/z3-fork + flavor: | + latest=auto + prefix=ubuntu-20.04-bare-z3- + tags: | + type=schedule,pattern={{date 'YYYYMMDD'}} + type=ref,event=tag + type=edge + type=sha,prefix=ubuntu-20.04-bare-z3-sha- + - name: Build and push Bare Z3 Docker Image + uses: docker/build-push-action@v2.7.0 + with: + context: . + push: true + target: bare-z3 + file: ./docker/ubuntu-20-04.Dockerfile + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + # ------------------------------ + # Repo description on Docker Hub + # ------------------------------ + - name: Update repo description + uses: peter-evans/dockerhub-description@v2 + with: + repository: deemetree/z3-fork + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + short-description: ${{ github.event.repository.description }} + readme-filepath: ./docker/README.md From 7d311ac2effb9f6a63477023e1f335ce101e33d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Dec 2021 13:44:40 -0800 Subject: [PATCH 20/88] use netstandard 2.0 per recommendations seems that now the recommended starting point is 2.0 and not lower. --- scripts/mk_nuget_task.py | 6 +++--- src/sat/smt/fpa_solver.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py index 69b67abc9..1143110aa 100644 --- a/scripts/mk_nuget_task.py +++ b/scripts/mk_nuget_task.py @@ -65,7 +65,7 @@ def unpack(packages, symbols): mk_dir(f"out/runtimes/{dst}/native") replace(f"{tmp}/{package_dir}/bin/libz3.{ext}", f"out/runtimes/{dst}/native/libz3.{ext}") if "x64-win" in f: - mk_dir("out/lib/netstandard1.4/") + mk_dir("out/lib/netstandard2.0/") if symbols: zip_ref.extract(f"{package_dir}/bin/libz3.pdb", f"{tmp}") replace(f"{tmp}/{package_dir}/bin/libz3.pdb", f"out/runtimes/{dst}/native/libz3.pdb") @@ -74,7 +74,7 @@ def unpack(packages, symbols): files += ["Microsoft.Z3.pdb", "Microsoft.Z3.xml"] for b in files: zip_ref.extract(f"{package_dir}/bin/{b}", f"{tmp}") - replace(f"{tmp}/{package_dir}/bin/{b}", f"out/lib/netstandard1.4/{b}") + replace(f"{tmp}/{package_dir}/bin/{b}", f"out/lib/netstandard2.0/{b}") def mk_targets(source_root): mk_dir("out/build") @@ -107,7 +107,7 @@ Linux Dependencies: true en - + """.format(version, repo, branch, commit) diff --git a/src/sat/smt/fpa_solver.cpp b/src/sat/smt/fpa_solver.cpp index f655a0241..55e41fea4 100644 --- a/src/sat/smt/fpa_solver.cpp +++ b/src/sat/smt/fpa_solver.cpp @@ -269,7 +269,7 @@ namespace fpa { expr* xe = e_x->get_expr(); expr* ye = e_y->get_expr(); - if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye)) + if (fu.is_bvwrap(xe) || fu.is_bvwrap(ye)) return; expr_ref xc = convert(xe); From ec3e2960501bbeef7a1299bfb7a8eef6d9136765 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Dec 2021 17:33:35 -0800 Subject: [PATCH 21/88] Update docker-image.yml (#5739) * Update docker-image.yml towards tweaking script to use ghcr * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml change usr/pwd to names that are more descriptive * Update docker-image.yml rename back to use DOCKER prefix it remains to bind to ghcr.io instead of docker.io * Update ubuntu-20-04.Dockerfile try to use ghcr instead of docker.io * Update docker-image.yml try with chcr token * Update docker-image.yml * Update docker-image.yml * Update docker-image.yml * Update ubuntu-20-04.Dockerfile * Update docker-image.yml --- .github/workflows/docker-image.yml | 31 ++++++++++++++++-------------- docker/ubuntu-20-04.Dockerfile | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index fa02c0aec..843b1c75e 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -7,15 +7,17 @@ on: jobs: push_to_registry: - name: Push Docker image to Docker Hub + name: Push Docker image to GitHub Docker registry runs-on: ubuntu-latest + steps: - - name: Check out the repo + - name: Check out the repo uses: actions/checkout@v2 - - name: Log in to Docker Hub + - name: Log in to GitHub Docker registry uses: docker/login-action@v1 with: + registry: ghcr.io username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -26,7 +28,7 @@ jobs: id: meta uses: docker/metadata-action@v3 with: - images: deemetree/z3-fork + images: ghcr.io/z3prover/z3 flavor: | latest=auto prefix=ubuntu-20.04-bare-z3- @@ -37,7 +39,7 @@ jobs: type=sha,prefix=ubuntu-20.04-bare-z3-sha- - name: Build and push Bare Z3 Docker Image uses: docker/build-push-action@v2.7.0 - with: + with: context: . push: true target: bare-z3 @@ -46,13 +48,14 @@ jobs: labels: ${{ steps.meta.outputs.labels }} # ------------------------------ - # Repo description on Docker Hub + # Repo description on GHCR # ------------------------------ - - name: Update repo description - uses: peter-evans/dockerhub-description@v2 - with: - repository: deemetree/z3-fork - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - short-description: ${{ github.event.repository.description }} - readme-filepath: ./docker/README.md +# - name: Update repo description +# uses: peter-evans/dockerhub-description@v2 +# with: +# registry: ghcr.io +# repository: z3prover/z3 +# username: ${{ secrets.DOCKER_USERNAME }} +# password: ${{ secrets.DOCKER_PASSWORD }} +# short-description: ${{ github.event.repository.description }} +# readme-filepath: ./docker/README.md diff --git a/docker/ubuntu-20-04.Dockerfile b/docker/ubuntu-20-04.Dockerfile index 7f20b753f..6a37d05c0 100644 --- a/docker/ubuntu-20-04.Dockerfile +++ b/docker/ubuntu-20-04.Dockerfile @@ -42,4 +42,4 @@ ENTRYPOINT [ "z3" ] # ... # TODO(optional): introduce C/C++ -binding stage -# ... \ No newline at end of file +# ... From 5a77c30ce0ab283edd6478596c49f0c41f1358b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Dec 2021 17:36:28 -0800 Subject: [PATCH 22/88] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c5af803b..3cd3478be 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,12 @@ See the [release notes](RELEASE_NOTES) for notes on various stable releases of Z ## Build status -| Azure Pipelines | Code Coverage | Open Bugs | Android Build | WASM Build | +| Azure Pipelines | Code Coverage | Open Bugs | Android Build | WASM Build | | --------------- | --------------|-----------|---------------|------------| | [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | [![Open Issues](https://github.com/Z3Prover/z3/actions/workflows/wip.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wip.yml) |[![Android Build](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml) | [![WASM Build](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml) | +Docker image. + [1]: #building-z3-on-windows-using-visual-studio-command-prompt [2]: #building-z3-using-make-and-gccclang [3]: #building-z3-using-cmake From 76e8e5720484374ba1d33e1be16d912ea9c64388 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Dec 2021 13:12:50 -0800 Subject: [PATCH 23/88] Update azure-pipelines.yml for Azure Pipelines remove flaky MacOS build tests --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f6753c09b..0057add97 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -310,8 +310,8 @@ jobs: eval `opam config env` make -j3 make -j3 _ex_ml_example_post_install - ./ml_example_shared.byte - ./ml_example_shared_custom.byte + # ./ml_example_shared.byte + # ./ml_example_shared_custom.byte # ./ml_example_shared cd .. # Skip as dead-slow in debug mode: From fcee2f5aa5ff6c14b26374f0b863af004420b6dd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 Dec 2021 14:49:33 -0800 Subject: [PATCH 24/88] revert relevancy2 --- src/sat/smt/euf_relevancy.cpp | 47 +-------------------------------- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/euf_solver.h | 3 +-- src/sat/smt/sat_dual_solver.cpp | 1 + 4 files changed, 4 insertions(+), 49 deletions(-) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 50804e538..655f2f5fe 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -89,7 +89,7 @@ namespace euf { m_dual_solver->track_relevancy(v); } - bool solver::init_relevancy1() { + bool solver::init_relevancy() { m_relevant_expr_ids.reset(); if (!relevancy_enabled()) return true; @@ -113,51 +113,6 @@ namespace euf { m_relevant_todo.push_back(e); } - - bool solver::init_relevancy2() { - m_relevant_expr_ids.reset(); - if (!relevancy_enabled()) - return true; - init_relevant_expr_ids(); - for (unsigned i = 0; i < s().trail_size(); ++i) { - sat::literal l = s().trail_literal(i); - auto v = l.var(); - auto j = s().get_justification(v); - switch (j.get_kind()) { - case sat::justification::kind::BINARY: - case sat::justification::kind::TERNARY: - case sat::justification::kind::CLAUSE: - case sat::justification::kind::EXT_JUSTIFICATION: - push_relevant(l.var()); - break; - case sat::justification::kind::NONE: - for (auto const& w : s().get_wlist(~l)) { - if (w.is_binary_non_learned_clause()) { - if (is_propagated(w.get_literal())) - continue; - } - else if (w.is_binary_clause()) - continue; - else if (w.is_ternary_clause()) { - if (is_propagated(w.get_literal1())) - continue; - if (is_propagated(w.get_literal2())) - continue; - } - else if (w.is_clause()) { - if (is_propagated(w.get_blocked_literal())) - continue; - } - push_relevant(l.var()); - break; - } - break; - } - } - relevant_subterms(); - return true; - } - bool solver::is_propagated(sat::literal lit) { return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none(); } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 1de9a0b0f..bbdd6ce0e 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -459,7 +459,7 @@ namespace euf { if (unit_propagate()) return sat::check_result::CR_CONTINUE; - if (!init_relevancy1()) + if (!init_relevancy()) give_up = true; unsigned num_nodes = m_egraph.num_nodes(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 8eef21bac..114cfbd8c 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -185,8 +185,7 @@ namespace euf { bool_vector m_relevant_visited; ptr_vector m_relevant_todo; void ensure_dual_solver(); - bool init_relevancy1(); - bool init_relevancy2(); + bool init_relevancy(); void relevant_subterms(); void init_relevant_expr_ids(); void push_relevant(sat::bool_var v); diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 86d73a2d8..9be5c3f01 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -149,6 +149,7 @@ namespace sat { if (is_sat == l_true) { TRACE("dual", display(s, tout); s.display(tout);); IF_VERBOSE(0, verbose_stream() << "unexpected SAT\n"); + IF_VERBOSE(0, display(s, verbose_stream()); s.display(verbose_stream());); UNREACHABLE(); return false; } From 0bd67257114029ef0b792bf468275500a8e4d517 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Dec 2021 15:06:04 -0800 Subject: [PATCH 25/88] #5641 mark all literals duplicated in dual solver as external --- src/sat/smt/euf_relevancy.cpp | 4 ++-- src/sat/smt/sat_dual_solver.cpp | 15 +++++++++------ src/sat/smt/sat_dual_solver.h | 9 +++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 655f2f5fe..e722e6412 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -59,7 +59,7 @@ namespace euf { void solver::ensure_dual_solver() { if (m_dual_solver) return; - m_dual_solver = alloc(sat::dual_solver, s().rlimit()); + m_dual_solver = alloc(sat::dual_solver, s(), s().rlimit()); for (unsigned i = s().num_user_scopes(); i-- > 0; ) m_dual_solver->push(); } @@ -95,7 +95,7 @@ namespace euf { return true; if (!m_dual_solver) return true; - if (!(*m_dual_solver)(s())) + if (!(*m_dual_solver)()) return false; init_relevant_expr_ids(); diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 9be5c3f01..3b6dea6f5 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -18,7 +18,8 @@ Author: namespace sat { - dual_solver::dual_solver(reslimit& l): + dual_solver::dual_solver(solver& s, reslimit& l): + s(s), m_solver(m_params, l) { SASSERT(!m_solver.get_config().m_drat); @@ -69,6 +70,7 @@ namespace sat { if (null_bool_var == w) { w = m_solver.mk_var(); m_solver.set_external(w); + s.set_external(v); m_ext2var.setx(v, w, null_bool_var); m_var2ext.setx(w, v, null_bool_var); m_vars.push_back(v); @@ -122,7 +124,7 @@ namespace sat { m_solver.mk_clause(sz, m_lits.data(), status::input()); } - void dual_solver::add_assumptions(solver const& s) { + void dual_solver::add_assumptions() { flush(); m_lits.reset(); for (bool_var v : m_tracked_vars) @@ -134,14 +136,14 @@ namespace sat { } } - bool dual_solver::operator()(solver const& s) { + bool dual_solver::operator()() { m_core.reset(); m_core.append(m_units); if (m_roots.empty()) return true; m_solver.user_push(); m_solver.add_clause(m_roots.size(), m_roots.data(), status::input()); - add_assumptions(s); + add_assumptions(); lbool is_sat = m_solver.check(m_lits.size(), m_lits.data()); if (is_sat == l_false) for (literal lit : m_solver.get_core()) @@ -149,7 +151,8 @@ namespace sat { if (is_sat == l_true) { TRACE("dual", display(s, tout); s.display(tout);); IF_VERBOSE(0, verbose_stream() << "unexpected SAT\n"); - IF_VERBOSE(0, display(s, verbose_stream()); s.display(verbose_stream());); + IF_VERBOSE(0, verbose_stream() << "assumptions: " << m_lits << "\n"); + IF_VERBOSE(0, display(verbose_stream()); s.display(verbose_stream());); UNREACHABLE(); return false; } @@ -158,7 +161,7 @@ namespace sat { return is_sat == l_false; } - std::ostream& dual_solver::display(solver const& s, std::ostream& out) const { + std::ostream& dual_solver::display(std::ostream& out) const { for (unsigned v = 0; v < m_solver.num_vars(); ++v) { bool_var w = m_var2ext.get(v, null_bool_var); if (w == null_bool_var) diff --git a/src/sat/smt/sat_dual_solver.h b/src/sat/smt/sat_dual_solver.h index 08a31084e..d9b43f7af 100644 --- a/src/sat/smt/sat_dual_solver.h +++ b/src/sat/smt/sat_dual_solver.h @@ -29,6 +29,7 @@ namespace sat { set_bool("core.minimize", false); } }; + solver& s; dual_params m_params; solver m_solver; lim_svector m_units, m_roots; @@ -46,14 +47,14 @@ namespace sat { literal ext2lit(literal lit); literal lit2ext(literal lit); - void add_assumptions(solver const& s); + void add_assumptions(); - std::ostream& display(solver const& s, std::ostream& out) const; + std::ostream& display(std::ostream& out) const; void flush(); public: - dual_solver(reslimit& l); + dual_solver(solver& s, reslimit& l); void push(); void pop(unsigned num_scopes); @@ -76,7 +77,7 @@ namespace sat { /* * Extract a minimized subset of relevant literals from a model for s. */ - bool operator()(solver const& s); + bool operator()(); literal_vector const& core() const { return m_core; } }; From d88f125818b716aa4595d5bf44bddd343e283dfc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 26 Dec 2021 15:24:03 -0800 Subject: [PATCH 26/88] build --- src/sat/smt/sat_dual_solver.cpp | 2 +- src/smt/smt_relevancy.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp index 3b6dea6f5..d4b93b90c 100644 --- a/src/sat/smt/sat_dual_solver.cpp +++ b/src/sat/smt/sat_dual_solver.cpp @@ -149,7 +149,7 @@ namespace sat { for (literal lit : m_solver.get_core()) m_core.push_back(lit2ext(lit)); if (is_sat == l_true) { - TRACE("dual", display(s, tout); s.display(tout);); + TRACE("dual", display(tout); s.display(tout);); IF_VERBOSE(0, verbose_stream() << "unexpected SAT\n"); IF_VERBOSE(0, verbose_stream() << "assumptions: " << m_lits << "\n"); IF_VERBOSE(0, display(verbose_stream()); s.display(verbose_stream());); diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 6d20072cb..9ad2a17ed 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -378,9 +378,7 @@ namespace smt { break; case l_true: { expr * true_arg = nullptr; - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = n->get_arg(i); + for (expr* arg : *n) { if (m_context.find_assignment(arg) == l_true) { if (is_relevant_core(arg)) return; @@ -402,9 +400,7 @@ namespace smt { switch (val) { case l_false: { expr * false_arg = nullptr; - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = n->get_arg(i); + for (expr* arg : *n) { if (m_context.find_assignment(arg) == l_false) { if (is_relevant_core(arg)) return; From 42f206171d0df032ea110743ee3c761edf571a26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Dec 2021 15:10:09 -0800 Subject: [PATCH 27/88] fix #5741 --- src/tactic/core/pb_preprocess_tactic.cpp | 2 +- src/tactic/goal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/core/pb_preprocess_tactic.cpp b/src/tactic/core/pb_preprocess_tactic.cpp index ef3db804b..1d40a91c7 100644 --- a/src/tactic/core/pb_preprocess_tactic.cpp +++ b/src/tactic/core/pb_preprocess_tactic.cpp @@ -605,7 +605,7 @@ private: sub.insert(e, v); expr_ref tmp(m); m_r.set_substitution(&sub); - for (unsigned i = 0; i < positions.size(); ++i) { + for (unsigned i = 0; !g->inconsistent() && i < positions.size(); ++i) { unsigned idx = positions[i]; expr_ref f(m); proof_ref new_pr(m); diff --git a/src/tactic/goal.h b/src/tactic/goal.h index f7f927bb3..f32e4a66b 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -119,7 +119,7 @@ public: unsigned num_exprs() const; - expr * form(unsigned i) const { return m().get(m_forms, i); } + expr * form(unsigned i) const { return inconsistent() ? m().mk_false() : m().get(m_forms, i); } proof * pr(unsigned i) const { return m().size(m_proofs) > i ? static_cast(m().get(m_proofs, i)) : nullptr; } expr_dependency * dep(unsigned i) const { return unsat_core_enabled() ? m().get(m_dependencies, i) : nullptr; } From 6f1be0999361473e727bdd17ac53fa6f6ceb2842 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Dec 2021 15:10:33 -0800 Subject: [PATCH 28/88] add direct and incremental relevancy propagator --- src/sat/smt/CMakeLists.txt | 1 + src/sat/smt/smt_relevancy.cpp | 228 ++++++++++++++++++++++++++++++++++ src/sat/smt/smt_relevancy.h | 143 +++++++++++++++++++++ 3 files changed, 372 insertions(+) create mode 100644 src/sat/smt/smt_relevancy.cpp create mode 100644 src/sat/smt/smt_relevancy.h diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 43b91b2f2..01681a6b1 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -40,6 +40,7 @@ z3_add_component(sat_smt recfun_solver.cpp sat_dual_solver.cpp sat_th.cpp + smt_relevancy.cpp user_solver.cpp COMPONENT_DEPENDENCIES sat diff --git a/src/sat/smt/smt_relevancy.cpp b/src/sat/smt/smt_relevancy.cpp new file mode 100644 index 000000000..21d570dd2 --- /dev/null +++ b/src/sat/smt/smt_relevancy.cpp @@ -0,0 +1,228 @@ +/*++ +Copyright (c) 2020 Microsoft Corporation + +Module Name: + + relevancy.cpp + +Abstract: + + Relevancy propagation + +Author: + + Nikolaj Bjorner (nbjorner) 2021-12-27 + + + +--*/ +#include "sat/sat_solver.h" +#include "sat/smt/euf_solver.h" +#include "sat/smt/smt_relevancy.h" + + +namespace smt { + + relevancy::relevancy(euf::solver& ctx): ctx(ctx) { + m_enabled = ctx.relevancy_enabled(); + } + + void relevancy::relevant_eh(euf::enode* n) { + // callback into ctx. + } + + void relevancy::relevant_eh(sat::literal lit) { + // callback into ctx. + } + + void relevancy::pop(unsigned n) { + if (n <= m_num_scopes) { + m_num_scopes -= n; + return; + } + else if (m_num_scopes > 0) { + n -= m_num_scopes; + m_num_scopes = 0; + } + SASSERT(n > 0); + unsigned sz = m_lim[m_lim.size() - n]; + for (unsigned i = m_trail.size(); i-- > sz; ) { + auto [u, idx] = m_trail[i]; + switch (u) { + case update::relevant_expr: + m_relevant_expr_ids[idx] = false; + m_queue.pop_back(); + break; + case update::relevant_var: + m_relevant_var_ids[idx] = false; + m_queue.pop_back(); + break; + case update::add_clause: { + sat::clause* c = m_clauses.back(); + for (sat::literal lit : *c) { + SASSERT(m_occurs[lit.index()] == m_clauses.size() - 1); + m_occurs[lit.index()].pop_back(); + } + m_clauses.pop_back(); + m_roots.pop_back(); + m_alloc.del_clause(c); + break; + } + case update::set_root: + m_roots[idx] = false; + break; + default: + UNREACHABLE(); + break; + } + } + m_trail.shrink(sz); + m_lim.shrink(m_lim.size() - n); + } + + void relevancy::add_root(unsigned n, sat::literal const* lits) { + if (!m_enabled) + return; + flush(); + sat::literal true_lit = sat::null_literal; + for (unsigned i = 0; i < n; ++i) { + if (ctx.s().value(lits[i]) == l_true) { + if (is_relevant(lits[i])) + return; + true_lit = lits[i]; + } + } + if (true_lit != sat::null_literal) { + mark_relevant(true_lit); + return; + } + + sat::clause cl = *m_alloc.mk_clause(n, lits, false); + unsigned sz = m_clauses.size(); + m_clauses.push_back(&cl); + m_roots.push_back(true); + m_trail.push_back(std::make_pair(update::add_clause, 0)); + for (sat::literal lit : cl) + occurs(lit).push_back(sz); + } + + void relevancy::add_def(unsigned n, sat::literal const* lits) { + if (!m_enabled) + return; + flush(); + for (unsigned i = 0; i < n; ++i) { + if (ctx.s().value(lits[i]) == l_false && is_relevant(lits[i])) { + add_root(n, lits); + return; + } + } + sat::clause cl = *m_alloc.mk_clause(n, lits, false); + unsigned sz = m_clauses.size(); + m_clauses.push_back(&cl); + m_roots.push_back(false); + m_trail.push_back(std::make_pair(update::add_clause, 0)); + for (sat::literal lit : cl) + occurs(lit).push_back(sz); + } + + void relevancy::assign(sat::literal lit) { + if (!m_enabled) + return; + flush(); + if (ctx.s().lvl(lit) == 0) { + mark_relevant(lit); + return; + } + for (auto idx : occurs(lit)) { + if (!m_roots[idx]) + continue; + for (sat::literal lit2 : *m_clauses[idx]) + if (lit2 != lit && ctx.s().value(lit2) == l_true && is_relevant(lit2)) + goto next; + mark_relevant(lit); + return; + next: + ; + } + } + + void relevancy::propagate() { + if (!m_enabled) + return; + flush(); + if (m_qhead == m_queue.size()) + return; + m_trail.push_back(std::make_pair(update::set_qhead, m_qhead)); + while (m_qhead < m_queue.size() && !ctx.s().inconsistent() && ctx.get_manager().inc()) { + auto [lit, n] = m_queue[m_qhead++]; + SASSERT(n || lit != sat::null_literal); + SASSERT(!n || lit == sat::null_literal); + if (n) + propagate_relevant(n); + else + propagate_relevant(lit); + } + } + + void relevancy::mark_relevant(euf::enode* n) { + if (!m_enabled) + return; + flush(); + if (is_relevant(n)) + return; + for (euf::enode* sib : euf::enode_class(n)) + set_relevant(sib); + } + + void relevancy::set_relevant(euf::enode* n) { + if (is_relevant(n)) + return; + m_relevant_expr_ids.setx(n->get_expr_id(), true, false); + m_trail.push_back(std::make_pair(update::relevant_expr, n->get_expr_id())); + m_queue.push_back(std::make_pair(sat::null_literal, n)); + } + + void relevancy::mark_relevant(sat::literal lit) { + if (!m_enabled) + return; + flush(); + if (is_relevant(lit)) + return; + m_relevant_var_ids.setx(lit.var(), true, false); + m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); + m_queue.push_back(std::make_pair(lit, nullptr)); + } + + void relevancy::propagate_relevant(sat::literal lit) { + relevant_eh(lit); + for (auto idx : occurs(~lit)) { + if (m_roots[idx]) + continue; + sat::clause& cl = *m_clauses[idx]; + sat::literal true_lit = sat::null_literal; + for (sat::literal lit2 : cl) { + if (ctx.s().value(lit2) == l_true) { + if (is_relevant(lit2)) + goto next; + true_lit = lit2; + } + } + + if (true_lit != sat::null_literal) + mark_relevant(true_lit); + else { + m_trail.push_back(std::make_pair(update::set_root, idx)); + m_roots[idx] = true; + } + next: + ; + } + } + + void relevancy::propagate_relevant(euf::enode* n) { + relevant_eh(n); + for (euf::enode* arg : euf::enode_args(n)) + mark_relevant(arg); + } + +} diff --git a/src/sat/smt/smt_relevancy.h b/src/sat/smt/smt_relevancy.h new file mode 100644 index 000000000..5532cd5a3 --- /dev/null +++ b/src/sat/smt/smt_relevancy.h @@ -0,0 +1,143 @@ +/*++ +Copyright (c) 2020 Microsoft Corporation + +Module Name: + + relevancy.h + +Abstract: + + Relevancy propagation + +Author: + + Nikolaj Bjorner (nbjorner) 2021-12-27 + + +Clauses are split into two parts: + +- Roots +- Defs + +The state transitions are: + +- A literal lit is assigned: + lit appears positively in a Root clause R and no other literal in R are relevant. + -> + lit is set relevant + + lit is justified at level 0 + -> + lit is set relevant + +- An equality n1 = n2 is assigned: + n1 is relevant + -> + n2 is marked as relevant + +- A lit is set relevant: + -> + all clauses C in Defs where lit appears negatively are added to Roots + + - When a clause R is added to Roots: + R contains a positive literal lit that is relevant + -> + skip adding R to Roots + +- When a clause R is added to Roots: + R contains a positive literal lit, no positive literal in R are relevant + -> + lit is set relevant + +- When a clause C is added to Defs: + C contains a negative literal that is relevant + -> + Add C to Roots + +- When an expression is set relevant: + All non-relevant children above Boolean connectives are set relevant + If nodes are treated as Boolean connectives because they are clausified + to (=> cond (= n then)) and (=> (not cond) (= n else)) + +Replay: + - literals that are replayed in clauses that are marked relevant are + marked relevant again. + + - expressions corresponding to auxiliary clauses are added as auxiliary clauses. + + - TBD: Are root clauses added under a scope discarded? + The SAT solver re-initializes clauses on its own, should we just use this mechanism? + +Can a literal that is not in a root be set relevant? + - yes, if we propagate over expressions + +Do we need full watch lists instead of 2-watch lists? + - probably, but unclear. The dual SAT solver only uses 2-watch lists, but has uses a large clause for tracking + roots. + + + +--*/ +#pragma once +#include "sat/sat_solver.h" +#include "sat/smt/sat_th.h" + +namespace euf { + class solver; +} + +namespace smt { + + class relevancy { + euf::solver& ctx; + + enum class update { relevant_expr, relevant_var, add_clause, set_root, set_qhead }; + + bool m_enabled = false; + svector> m_trail; + unsigned_vector m_lim; + unsigned m_num_scopes = 0; + bool_vector m_relevant_expr_ids; // identifiers of relevant expressions + bool_vector m_relevant_var_ids; // identifiers of relevant Boolean variables + sat::clause_allocator m_alloc; + sat::clause_vector m_clauses; // clauses + bool_vector m_roots; // indicate if clause is a root + vector m_occurs; // where do literals occur + unsigned m_qhead = 0; // queue head for relevancy + svector> m_queue; // propagation queue for relevancy + + // callbacks during propagation + void relevant_eh(euf::enode* n); + void relevant_eh(sat::literal lit); + + void push_core() { m_lim.push_back(m_trail.size()); } + void flush() { for (; m_num_scopes > 0; --m_num_scopes) push_core(); } + + unsigned_vector& occurs(sat::literal lit) { m_occurs.reserve(lit.index() + 1); return m_occurs[lit.index()]; } + + void propagate_relevant(sat::literal lit); + + void propagate_relevant(euf::enode* n); + + void set_relevant(euf::enode* n); + + public: + relevancy(euf::solver& ctx); + + void push() { ++m_num_scopes; } + void pop(unsigned n); + + void add_root(unsigned n, sat::literal const* lits); + void add_def(unsigned n, sat::literal const* lits); + void assign(sat::literal lit); + void propagate(); + + void mark_relevant(euf::enode* n); + void mark_relevant(sat::literal lit); + + bool is_relevant(sat::literal lit) const { return !m_enabled || m_relevant_var_ids.get(lit.var(), false); } + bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); } + bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); } + + }; +} From 9527471967db4bb3fb66425e4f0b3e0fbcdd7f1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 27 Dec 2021 16:03:56 -0800 Subject: [PATCH 29/88] build Signed-off-by: Nikolaj Bjorner --- src/sat/smt/CMakeLists.txt | 2 +- src/sat/smt/euf_relevancy.cpp | 42 ++++++++++++++++++- src/sat/smt/euf_solver.cpp | 29 ++++++++++--- src/sat/smt/euf_solver.h | 13 ++++-- .../{smt_relevancy.cpp => smt_relevant.cpp} | 37 ++++++++++------ .../smt/{smt_relevancy.h => smt_relevant.h} | 3 +- 6 files changed, 100 insertions(+), 26 deletions(-) rename src/sat/smt/{smt_relevancy.cpp => smt_relevant.cpp} (88%) rename src/sat/smt/{smt_relevancy.h => smt_relevant.h} (97%) diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 01681a6b1..dc7f73c93 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -40,7 +40,7 @@ z3_add_component(sat_smt recfun_solver.cpp sat_dual_solver.cpp sat_th.cpp - smt_relevancy.cpp + smt_relevant.cpp user_solver.cpp COMPONENT_DEPENDENCIES sat diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index e722e6412..64aea0c8c 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -22,16 +22,25 @@ Author: namespace euf { - void solver::add_auto_relevant(expr* e) { + void solver::add_auto_relevant(sat::literal lit) { +#if NEW_RELEVANCY + m_relevancy.mark_relevant(lit); + return; +#endif if (!relevancy_enabled()) return; for (; m_auto_relevant_scopes > 0; --m_auto_relevant_scopes) m_auto_relevant_lim.push_back(m_auto_relevant.size()); // std::cout << "add-auto " << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; + expr* e = bool_var2expr(lit.var()); m_auto_relevant.push_back(e); } void solver::pop_relevant(unsigned n) { +#if NEW_RELEVANCY + m_relevancy.pop(n); + return; +#endif if (m_auto_relevant_scopes >= n) { m_auto_relevant_scopes -= n; return; @@ -45,18 +54,31 @@ namespace euf { } void solver::push_relevant() { +#if NEW_RELEVANCY + m_relevancy.push(); + return; +#endif ++m_auto_relevant_scopes; } bool solver::is_relevant(expr* e) const { +#if NEW_RELEVANCY + return m_relevancy.is_relevant(e); +#endif return m_relevant_expr_ids.get(e->get_id(), true); } bool solver::is_relevant(enode* n) const { +#if NEW_RELEVANCY + return m_relevancy.is_relevant(n); +#endif return m_relevant_expr_ids.get(n->get_expr_id(), true); } void solver::ensure_dual_solver() { +#if NEW_RELEVANCY + return; +#endif if (m_dual_solver) return; m_dual_solver = alloc(sat::dual_solver, s(), s().rlimit()); @@ -71,6 +93,10 @@ namespace euf { * not tracked. */ void solver::add_root(unsigned n, sat::literal const* lits) { +#if NEW_RELEVANCY + m_relevancy.add_root(n, lits); + return; +#endif if (!relevancy_enabled()) return; ensure_dual_solver(); @@ -78,6 +104,10 @@ namespace euf { } void solver::add_aux(unsigned n, sat::literal const* lits) { +#if NEW_RELEVANCY + m_relevancy.add_def(n, lits); + return; +#endif if (!relevancy_enabled()) return; ensure_dual_solver(); @@ -85,11 +115,17 @@ namespace euf { } void solver::track_relevancy(sat::bool_var v) { +#if NEW_RELEVANCY + return; +#endif ensure_dual_solver(); m_dual_solver->track_relevancy(v); } bool solver::init_relevancy() { +#if NEW_RELEVANCY + return true; +#endif m_relevant_expr_ids.reset(); if (!relevancy_enabled()) return true; @@ -108,16 +144,19 @@ namespace euf { } void solver::push_relevant(sat::bool_var v) { + SASSERT(!NEW_RELEVANCY); expr* e = m_bool_var2expr.get(v, nullptr); if (e) m_relevant_todo.push_back(e); } bool solver::is_propagated(sat::literal lit) { + SASSERT(!NEW_RELEVANCY); return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none(); } void solver::init_relevant_expr_ids() { + SASSERT(!NEW_RELEVANCY); unsigned max_id = 0; for (enode* n : m_egraph.nodes()) max_id = std::max(max_id, n->get_expr_id()); @@ -127,6 +166,7 @@ namespace euf { } void solver::relevant_subterms() { + SASSERT(!NEW_RELEVANCY); ptr_vector& todo = m_relevant_todo; bool_vector& visited = m_relevant_visited; for (unsigned i = 0; i < todo.size(); ++i) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index bbdd6ce0e..2c602d205 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -41,6 +41,7 @@ namespace euf { extension(symbol("euf"), m.mk_family_id("euf")), m(m), si(si), + m_relevancy(*this), m_egraph(m), m_trail(), m_rewriter(m), @@ -183,7 +184,7 @@ namespace euf { } void solver::propagate(literal lit, ext_justification_idx idx) { - add_auto_relevant(bool_var2expr(lit.var())); + add_auto_relevant(lit); s().assign(lit, sat::justification::mk_ext_justification(s().scope_lvl(), idx)); } @@ -243,10 +244,17 @@ namespace euf { bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) { if (a->get_root() == b->get_root()) return false; - m_egraph.merge(a, b, to_ptr(idx)); + merge(a, b, to_ptr(idx)); return true; } + void solver::merge(enode* a, enode* b, void* r) { +#if NEW_RELEVANCY + m_relevancy.merge(a, b); +#endif + m_egraph.merge(a, b, r); + } + void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) { expr* e = nullptr; euf::enode* n = nullptr; @@ -286,6 +294,12 @@ namespace euf { } void solver::asserted(literal l) { +#if NEW_RELEVANCY + if (!m_relevancy.is_relevant(l)) { + m_relevancy.asserted(l); + return; + } +#endif expr* e = m_bool_var2expr.get(l.var(), nullptr); TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); if (!e) @@ -306,14 +320,14 @@ namespace euf { euf::enode* r = n->get_root(); euf::enode* rb = sign ? mk_true() : mk_false(); sat::literal rl(r->bool_var(), r->value() == l_false); - m_egraph.merge(n, nb, c); - m_egraph.merge(r, rb, to_ptr(rl)); + merge(n, nb, c); + merge(r, rb, to_ptr(rl)); SASSERT(m_egraph.inconsistent()); return; } if (n->merge_tf()) { euf::enode* nb = sign ? mk_false() : mk_true(); - m_egraph.merge(n, nb, c); + merge(n, nb, c); } if (n->is_equality()) { SASSERT(!m.is_iff(e)); @@ -321,7 +335,7 @@ namespace euf { if (sign) m_egraph.new_diseq(n); else - m_egraph.merge(n->get_arg(0), n->get_arg(1), c); + merge(n->get_arg(0), n->get_arg(1), c); } } @@ -329,6 +343,9 @@ namespace euf { bool solver::unit_propagate() { bool propagated = false; while (!s().inconsistent()) { +#if NEW_RELEVANCY + m_relevancy.propagate(); +#endif if (m_egraph.inconsistent()) { unsigned lvl = s().scope_lvl(); s().set_conflict(sat::justification::mk_ext_justification(lvl, conflict_constraint().to_index())); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 114cfbd8c..1396e00fb 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -28,8 +28,11 @@ Author: #include "sat/smt/sat_dual_solver.h" #include "sat/smt/euf_ackerman.h" #include "sat/smt/user_solver.h" +#include "sat/smt/smt_relevant.h" #include "smt/params/smt_params.h" +#define NEW_RELEVANCY 0 + namespace euf { typedef sat::literal literal; typedef sat::ext_constraint_idx ext_constraint_idx; @@ -91,6 +94,7 @@ namespace euf { std::function<::solver*(void)> m_mk_solver; ast_manager& m; sat::sat_internalizer& si; + smt::relevancy m_relevancy; smt_params m_config; euf::egraph m_egraph; trail_stack m_trail; @@ -289,6 +293,7 @@ namespace euf { void propagate(literal lit, ext_justification_idx idx); bool propagate(enode* a, enode* b, ext_justification_idx idx); + void merge(enode* a, enode* b, void* r); void set_conflict(ext_justification_idx idx); void propagate(literal lit, th_explain* p) { propagate(lit, p->to_index()); } @@ -367,14 +372,14 @@ namespace euf { bool is_shared(euf::enode* n) const; // relevancy - bool m_relevancy = true; + bool m_relevancy_enabled = true; scoped_ptr m_dual_solver; ptr_vector m_auto_relevant; unsigned_vector m_auto_relevant_lim; unsigned m_auto_relevant_scopes = 0; - bool relevancy_enabled() const { return m_relevancy && get_config().m_relevancy_lvl > 0; } - void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy = false; } + bool relevancy_enabled() const { return m_relevancy_enabled && get_config().m_relevancy_lvl > 0; } + void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy_enabled = false; } void add_root(unsigned n, sat::literal const* lits); void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } @@ -387,7 +392,7 @@ namespace euf { void track_relevancy(sat::bool_var v); bool is_relevant(expr* e) const; bool is_relevant(enode* n) const; - void add_auto_relevant(expr* e); + void add_auto_relevant(sat::literal lit); void pop_relevant(unsigned n); void push_relevant(); diff --git a/src/sat/smt/smt_relevancy.cpp b/src/sat/smt/smt_relevant.cpp similarity index 88% rename from src/sat/smt/smt_relevancy.cpp rename to src/sat/smt/smt_relevant.cpp index 21d570dd2..d70d37beb 100644 --- a/src/sat/smt/smt_relevancy.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -13,12 +13,10 @@ Author: Nikolaj Bjorner (nbjorner) 2021-12-27 - - --*/ #include "sat/sat_solver.h" #include "sat/smt/euf_solver.h" -#include "sat/smt/smt_relevancy.h" +#include "sat/smt/smt_relevant.h" namespace smt { @@ -28,11 +26,13 @@ namespace smt { } void relevancy::relevant_eh(euf::enode* n) { - // callback into ctx. + // nothing } void relevancy::relevant_eh(sat::literal lit) { - // callback into ctx. + SASSERT(ctx.s().value(lit) == l_true); + SASSERT(is_relevant(lit)); + ctx.asserted(lit); } void relevancy::pop(unsigned n) { @@ -97,12 +97,12 @@ namespace smt { return; } - sat::clause cl = *m_alloc.mk_clause(n, lits, false); + sat::clause* cl = m_alloc.mk_clause(n, lits, false); unsigned sz = m_clauses.size(); - m_clauses.push_back(&cl); + m_clauses.push_back(cl); m_roots.push_back(true); m_trail.push_back(std::make_pair(update::add_clause, 0)); - for (sat::literal lit : cl) + for (sat::literal lit : *cl) occurs(lit).push_back(sz); } @@ -116,16 +116,16 @@ namespace smt { return; } } - sat::clause cl = *m_alloc.mk_clause(n, lits, false); + sat::clause* cl = m_alloc.mk_clause(n, lits, false); unsigned sz = m_clauses.size(); - m_clauses.push_back(&cl); + m_clauses.push_back(cl); m_roots.push_back(false); m_trail.push_back(std::make_pair(update::add_clause, 0)); - for (sat::literal lit : cl) + for (sat::literal lit : *cl) occurs(lit).push_back(sz); } - void relevancy::assign(sat::literal lit) { + void relevancy::asserted(sat::literal lit) { if (!m_enabled) return; flush(); @@ -163,6 +163,13 @@ namespace smt { propagate_relevant(lit); } } + + void relevancy::merge(euf::enode* n1, euf::enode* n2) { + if (is_relevant(n1)) + mark_relevant(n2); + else if (is_relevant(n2)) + mark_relevant(n1); + } void relevancy::mark_relevant(euf::enode* n) { if (!m_enabled) @@ -187,10 +194,13 @@ namespace smt { return; flush(); if (is_relevant(lit)) - return; + return; m_relevant_var_ids.setx(lit.var(), true, false); m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); m_queue.push_back(std::make_pair(lit, nullptr)); + euf::enode* n = nullptr; + if (n) + mark_relevant(n); } void relevancy::propagate_relevant(sat::literal lit) { @@ -221,6 +231,7 @@ namespace smt { void relevancy::propagate_relevant(euf::enode* n) { relevant_eh(n); + // if is_bool_op n, return; for (euf::enode* arg : euf::enode_args(n)) mark_relevant(arg); } diff --git a/src/sat/smt/smt_relevancy.h b/src/sat/smt/smt_relevant.h similarity index 97% rename from src/sat/smt/smt_relevancy.h rename to src/sat/smt/smt_relevant.h index 5532cd5a3..6faa66b0f 100644 --- a/src/sat/smt/smt_relevancy.h +++ b/src/sat/smt/smt_relevant.h @@ -129,11 +129,12 @@ namespace smt { void add_root(unsigned n, sat::literal const* lits); void add_def(unsigned n, sat::literal const* lits); - void assign(sat::literal lit); + void asserted(sat::literal lit); void propagate(); void mark_relevant(euf::enode* n); void mark_relevant(sat::literal lit); + void merge(euf::enode* n1, euf::enode* n2); bool is_relevant(sat::literal lit) const { return !m_enabled || m_relevant_var_ids.get(lit.var(), false); } bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); } From 28bce8f09ccdd194c8ebcab1a128edc0e8e2d721 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 11:00:02 -0800 Subject: [PATCH 30/88] working on relevant --- src/ast/euf/euf_egraph.cpp | 4 +- src/ast/euf/euf_egraph.h | 5 ++- src/sat/smt/euf_relevancy.cpp | 73 ++++++++++++++++------------------- src/sat/smt/euf_solver.cpp | 53 ++++++++++++------------- src/sat/smt/euf_solver.h | 8 ++-- src/sat/smt/q_ematch.cpp | 12 +++++- src/sat/smt/q_ematch.h | 3 +- src/sat/smt/q_solver.h | 1 + src/sat/smt/sat_th.h | 2 + src/sat/smt/smt_relevant.cpp | 43 ++++++++++++--------- src/sat/smt/smt_relevant.h | 15 ++++--- 11 files changed, 121 insertions(+), 98 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 1f8e14565..f1e51ee1d 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -446,8 +446,8 @@ namespace euf { r2->inc_class_size(r1->class_size()); merge_th_eq(r1, r2); reinsert_parents(r1, r2); - if (m_on_merge) - m_on_merge(r2, r1); + for (auto& cb : m_on_merge) + cb(r2, r1); } void egraph::remove_parents(enode* r1, enode* r2) { diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index 7c1f9e566..ef70fafd5 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -32,6 +32,7 @@ Notes: #include "ast/euf/euf_enode.h" #include "ast/euf/euf_etable.h" #include "ast/ast_ll_pp.h" +#include namespace euf { @@ -181,7 +182,7 @@ namespace euf { enode_vector m_todo; stats m_stats; bool m_uses_congruence = false; - std::function m_on_merge; + std::vector> m_on_merge; std::function m_on_make; std::function m_used_eq; std::function m_used_cc; @@ -293,7 +294,7 @@ namespace euf { void set_value(enode* n, lbool value); void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); } - void set_on_merge(std::function& on_merge) { m_on_merge = on_merge; } + void set_on_merge(std::function& on_merge) { m_on_merge.push_back(on_merge); } void set_on_make(std::function& on_make) { m_on_make = on_make; } void set_used_eq(std::function& used_eq) { m_used_eq = used_eq; } void set_used_cc(std::function& used_cc) { m_used_cc = used_cc; } diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 64aea0c8c..a15e7bacc 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -23,10 +23,10 @@ Author: namespace euf { void solver::add_auto_relevant(sat::literal lit) { -#if NEW_RELEVANCY - m_relevancy.mark_relevant(lit); - return; -#endif + if (m_relevancy.enabled()) { + m_relevancy.mark_relevant(lit); + return; + } if (!relevancy_enabled()) return; for (; m_auto_relevant_scopes > 0; --m_auto_relevant_scopes) @@ -37,10 +37,10 @@ namespace euf { } void solver::pop_relevant(unsigned n) { -#if NEW_RELEVANCY - m_relevancy.pop(n); - return; -#endif + if (m_relevancy.enabled()) { + m_relevancy.pop(n); + return; + } if (m_auto_relevant_scopes >= n) { m_auto_relevant_scopes -= n; return; @@ -54,31 +54,28 @@ namespace euf { } void solver::push_relevant() { -#if NEW_RELEVANCY - m_relevancy.push(); - return; -#endif + if (m_relevancy.enabled()) { + m_relevancy.push(); + return; + } ++m_auto_relevant_scopes; } bool solver::is_relevant(expr* e) const { -#if NEW_RELEVANCY - return m_relevancy.is_relevant(e); -#endif + if (m_relevancy.enabled()) + return m_relevancy.is_relevant(e); return m_relevant_expr_ids.get(e->get_id(), true); } bool solver::is_relevant(enode* n) const { -#if NEW_RELEVANCY - return m_relevancy.is_relevant(n); -#endif + if (m_relevancy.enabled()) + return m_relevancy.is_relevant(n); return m_relevant_expr_ids.get(n->get_expr_id(), true); } void solver::ensure_dual_solver() { -#if NEW_RELEVANCY - return; -#endif + if (m_relevancy.enabled()) + return; if (m_dual_solver) return; m_dual_solver = alloc(sat::dual_solver, s(), s().rlimit()); @@ -93,10 +90,10 @@ namespace euf { * not tracked. */ void solver::add_root(unsigned n, sat::literal const* lits) { -#if NEW_RELEVANCY - m_relevancy.add_root(n, lits); - return; -#endif + if (m_relevancy.enabled()) { + m_relevancy.add_root(n, lits); + return; + } if (!relevancy_enabled()) return; ensure_dual_solver(); @@ -104,10 +101,10 @@ namespace euf { } void solver::add_aux(unsigned n, sat::literal const* lits) { -#if NEW_RELEVANCY - m_relevancy.add_def(n, lits); - return; -#endif + if (m_relevancy.enabled()) { + m_relevancy.add_def(n, lits); + return; + } if (!relevancy_enabled()) return; ensure_dual_solver(); @@ -115,17 +112,15 @@ namespace euf { } void solver::track_relevancy(sat::bool_var v) { -#if NEW_RELEVANCY - return; -#endif + if (m_relevancy.enabled()) + return; ensure_dual_solver(); m_dual_solver->track_relevancy(v); } bool solver::init_relevancy() { -#if NEW_RELEVANCY - return true; -#endif + if (m_relevancy.enabled()) + return true; m_relevant_expr_ids.reset(); if (!relevancy_enabled()) return true; @@ -144,19 +139,19 @@ namespace euf { } void solver::push_relevant(sat::bool_var v) { - SASSERT(!NEW_RELEVANCY); + SASSERT(!m_relevancy.enabled()); expr* e = m_bool_var2expr.get(v, nullptr); if (e) m_relevant_todo.push_back(e); } bool solver::is_propagated(sat::literal lit) { - SASSERT(!NEW_RELEVANCY); + SASSERT(!m_relevancy.enabled()); return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none(); } void solver::init_relevant_expr_ids() { - SASSERT(!NEW_RELEVANCY); + SASSERT(!m_relevancy.enabled()); unsigned max_id = 0; for (enode* n : m_egraph.nodes()) max_id = std::max(max_id, n->get_expr_id()); @@ -166,7 +161,7 @@ namespace euf { } void solver::relevant_subterms() { - SASSERT(!NEW_RELEVANCY); + SASSERT(!m_relevancy.enabled()); ptr_vector& todo = m_relevant_todo; bool_vector& visited = m_relevant_visited; for (unsigned i = 0; i < todo.size(); ++i) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 2c602d205..ca931ce8f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -58,6 +58,14 @@ namespace euf { display_justification_ptr(out, reinterpret_cast(j)); }; m_egraph.set_display_justification(disp); + + if (m_relevancy.enabled()) { + std::function on_merge = + [&](enode* root, enode* other) { + m_relevancy.merge(root, other); + }; + m_egraph.set_on_merge(on_merge); + } } void solver::updt_params(params_ref const& p) { @@ -244,17 +252,10 @@ namespace euf { bool solver::propagate(enode* a, enode* b, ext_justification_idx idx) { if (a->get_root() == b->get_root()) return false; - merge(a, b, to_ptr(idx)); + m_egraph.merge(a, b, to_ptr(idx)); return true; } - void solver::merge(enode* a, enode* b, void* r) { -#if NEW_RELEVANCY - m_relevancy.merge(a, b); -#endif - m_egraph.merge(a, b, r); - } - void solver::get_antecedents(literal l, constraint& j, literal_vector& r, bool probing) { expr* e = nullptr; euf::enode* n = nullptr; @@ -294,12 +295,11 @@ namespace euf { } void solver::asserted(literal l) { -#if NEW_RELEVANCY - if (!m_relevancy.is_relevant(l)) { + if (m_relevancy.enabled() && !m_relevancy.is_relevant(l)) { m_relevancy.asserted(l); return; } -#endif + expr* e = m_bool_var2expr.get(l.var(), nullptr); TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); if (!e) @@ -320,14 +320,14 @@ namespace euf { euf::enode* r = n->get_root(); euf::enode* rb = sign ? mk_true() : mk_false(); sat::literal rl(r->bool_var(), r->value() == l_false); - merge(n, nb, c); - merge(r, rb, to_ptr(rl)); + m_egraph.merge(n, nb, c); + m_egraph.merge(r, rb, to_ptr(rl)); SASSERT(m_egraph.inconsistent()); return; } if (n->merge_tf()) { euf::enode* nb = sign ? mk_false() : mk_true(); - merge(n, nb, c); + m_egraph.merge(n, nb, c); } if (n->is_equality()) { SASSERT(!m.is_iff(e)); @@ -335,7 +335,7 @@ namespace euf { if (sign) m_egraph.new_diseq(n); else - merge(n->get_arg(0), n->get_arg(1), c); + m_egraph.merge(n->get_arg(0), n->get_arg(1), c); } } @@ -343,9 +343,8 @@ namespace euf { bool solver::unit_propagate() { bool propagated = false; while (!s().inconsistent()) { -#if NEW_RELEVANCY - m_relevancy.propagate(); -#endif + if (m_relevancy.enabled()) + m_relevancy.propagate(); if (m_egraph.inconsistent()) { unsigned lvl = s().scope_lvl(); s().set_conflict(sat::justification::mk_ext_justification(lvl, conflict_constraint().to_index())); @@ -362,9 +361,13 @@ namespace euf { if (m_solvers[i]->unit_propagate()) propagated1 = true; - if (!propagated1) - break; - propagated = true; + if (propagated1) { + propagated = true; + continue; + } + if (m_relevancy.enabled() && m_relevancy.can_propagate()) + continue; + break; } DEBUG_CODE(if (!propagated && !s().inconsistent()) check_missing_eq_propagation();); return propagated; @@ -439,12 +442,10 @@ namespace euf { void solver::propagate_th_eqs() { for (; m_egraph.has_th_eq() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_th_eq()) { th_eq eq = m_egraph.get_th_eq(); - if (eq.is_eq()) { - if (!is_self_propagated(eq)) - m_id2solver[eq.id()]->new_eq_eh(eq); - } - else + if (!eq.is_eq()) m_id2solver[eq.id()]->new_diseq_eh(eq); + else if (!is_self_propagated(eq)) + m_id2solver[eq.id()]->new_eq_eh(eq); } } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 1396e00fb..2145594f1 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -31,7 +31,6 @@ Author: #include "sat/smt/smt_relevant.h" #include "smt/params/smt_params.h" -#define NEW_RELEVANCY 0 namespace euf { typedef sat::literal literal; @@ -257,6 +256,10 @@ namespace euf { sat::sat_internalizer& get_si() { return si; } ast_manager& get_manager() { return m; } enode* get_enode(expr* e) const { return m_egraph.find(e); } + enode* bool_var2enode(sat::bool_var b) const { + expr* e = m_bool_var2expr.get(b); + return e ? get_enode(e) : nullptr; + } sat::literal expr2literal(expr* e) const { return enode2literal(get_enode(e)); } sat::literal enode2literal(enode* n) const { return sat::literal(n->bool_var(), false); } lbool value(enode* n) const { return s().value(enode2literal(n)); } @@ -293,7 +296,6 @@ namespace euf { void propagate(literal lit, ext_justification_idx idx); bool propagate(enode* a, enode* b, ext_justification_idx idx); - void merge(enode* a, enode* b, void* r); void set_conflict(ext_justification_idx idx); void propagate(literal lit, th_explain* p) { propagate(lit, p->to_index()); } @@ -395,7 +397,7 @@ namespace euf { void add_auto_relevant(sat::literal lit); void pop_relevant(unsigned n); void push_relevant(); - + smt::relevancy& relevancy() { return m_relevancy; } // model construction void update_model(model_ref& mdl); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index e4e01b964..a5f64f677 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -66,13 +66,21 @@ namespace q { }; std::function _on_make = [&](euf::enode* n) { - m_mam->add_node(n, false); + relevant_eh(n); + }; ctx.get_egraph().set_on_merge(_on_merge); - ctx.get_egraph().set_on_make(_on_make); + if (ctx.relevancy().enabled()) + ctx.get_egraph().set_on_make(_on_make); + else + ctx.relevancy().add_relevant(&s); m_mam = mam::mk(ctx, *this); } + void ematch::relevant_eh(euf::enode* n) { + m_mam->add_node(n, false); + } + void ematch::ensure_ground_enodes(expr* e) { mam::ground_subterms(e, m_ground); for (expr* g : m_ground) diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index 3cdcfc80e..0db541c1c 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -135,9 +135,10 @@ namespace q { bool unit_propagate(); - void add(quantifier* q); + void relevant_eh(euf::enode* n); + void collect_statistics(statistics& st) const; void get_antecedents(sat::literal l, sat::ext_justification_idx idx, sat::literal_vector& r, bool probing); diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index 934864669..5d6a52c8f 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -83,6 +83,7 @@ namespace q { void init_search() override; void finalize_model(model& mdl) override; bool is_shared(euf::theory_var v) const override { return true; } + void relevant_eh(euf::enode* n) override { m_ematch.relevant_eh(n); } ast_manager& get_manager() { return m; } sat::literal_vector const& universal() const { return m_universal; } diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 7e66a7156..fecb745c5 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -111,6 +111,8 @@ namespace euf { virtual void new_diseq_eh(euf::th_eq const& eq) {} + virtual void relevant_eh(euf::enode* n) {} + /** \brief Parametric theories (e.g. Arrays) should implement this method. */ diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index d70d37beb..9d118001c 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -3,7 +3,7 @@ Copyright (c) 2020 Microsoft Corporation Module Name: - relevancy.cpp + smt_relevant.cpp Abstract: @@ -22,11 +22,13 @@ Author: namespace smt { relevancy::relevancy(euf::solver& ctx): ctx(ctx) { - m_enabled = ctx.relevancy_enabled(); + m_enabled = ctx.get_config().m_relevancy_lvl > 2; } void relevancy::relevant_eh(euf::enode* n) { - // nothing + SASSERT(is_relevant(n)); + for (auto* th : m_relevant_eh) + th->relevant_eh(n); } void relevancy::relevant_eh(sat::literal lit) { @@ -102,8 +104,10 @@ namespace smt { m_clauses.push_back(cl); m_roots.push_back(true); m_trail.push_back(std::make_pair(update::add_clause, 0)); - for (sat::literal lit : *cl) + for (sat::literal lit : *cl) { + ctx.s().set_external(lit.var()); occurs(lit).push_back(sz); + } } void relevancy::add_def(unsigned n, sat::literal const* lits) { @@ -121,15 +125,17 @@ namespace smt { m_clauses.push_back(cl); m_roots.push_back(false); m_trail.push_back(std::make_pair(update::add_clause, 0)); - for (sat::literal lit : *cl) - occurs(lit).push_back(sz); + for (sat::literal lit : *cl) { + ctx.s().set_external(lit.var()); + occurs(lit).push_back(sz); + } } void relevancy::asserted(sat::literal lit) { if (!m_enabled) return; flush(); - if (ctx.s().lvl(lit) == 0) { + if (ctx.s().lvl(lit) <= ctx.s().search_lvl()) { mark_relevant(lit); return; } @@ -164,11 +170,11 @@ namespace smt { } } - void relevancy::merge(euf::enode* n1, euf::enode* n2) { - if (is_relevant(n1)) - mark_relevant(n2); - else if (is_relevant(n2)) - mark_relevant(n1); + void relevancy::merge(euf::enode* root, euf::enode* other) { + if (is_relevant(root)) + mark_relevant(other); + else if (is_relevant(other)) + mark_relevant(root); } void relevancy::mark_relevant(euf::enode* n) { @@ -177,6 +183,8 @@ namespace smt { flush(); if (is_relevant(n)) return; + if (ctx.get_si().is_bool_op(n->get_expr())) + return; for (euf::enode* sib : euf::enode_class(n)) set_relevant(sib); } @@ -195,12 +203,12 @@ namespace smt { flush(); if (is_relevant(lit)) return; + euf::enode* n = ctx.bool_var2enode(lit.var()); + if (n) + mark_relevant(n); m_relevant_var_ids.setx(lit.var(), true, false); m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); m_queue.push_back(std::make_pair(lit, nullptr)); - euf::enode* n = nullptr; - if (n) - mark_relevant(n); } void relevancy::propagate_relevant(sat::literal lit) { @@ -208,9 +216,9 @@ namespace smt { for (auto idx : occurs(~lit)) { if (m_roots[idx]) continue; - sat::clause& cl = *m_clauses[idx]; + sat::clause* cl = m_clauses[idx]; sat::literal true_lit = sat::null_literal; - for (sat::literal lit2 : cl) { + for (sat::literal lit2 : *cl) { if (ctx.s().value(lit2) == l_true) { if (is_relevant(lit2)) goto next; @@ -231,7 +239,6 @@ namespace smt { void relevancy::propagate_relevant(euf::enode* n) { relevant_eh(n); - // if is_bool_op n, return; for (euf::enode* arg : euf::enode_args(n)) mark_relevant(arg); } diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index 6faa66b0f..a20ca1b44 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -3,7 +3,7 @@ Copyright (c) 2020 Microsoft Corporation Module Name: - relevancy.h + smt_relevant.h Abstract: @@ -26,7 +26,7 @@ The state transitions are: -> lit is set relevant - lit is justified at level 0 + lit is justified at search level -> lit is set relevant @@ -39,7 +39,7 @@ The state transitions are: -> all clauses C in Defs where lit appears negatively are added to Roots - - When a clause R is added to Roots: +- When a clause R is added to Roots: R contains a positive literal lit that is relevant -> skip adding R to Roots @@ -72,7 +72,7 @@ Can a literal that is not in a root be set relevant? - yes, if we propagate over expressions Do we need full watch lists instead of 2-watch lists? - - probably, but unclear. The dual SAT solver only uses 2-watch lists, but has uses a large clause for tracking + - probably, but unclear. The dual SAT solver only uses 2-watch lists, but uses a large clause for tracking roots. @@ -105,6 +105,7 @@ namespace smt { vector m_occurs; // where do literals occur unsigned m_qhead = 0; // queue head for relevancy svector> m_queue; // propagation queue for relevancy + ptr_vector m_relevant_eh; // callbacks during propagation void relevant_eh(euf::enode* n); @@ -131,6 +132,7 @@ namespace smt { void add_def(unsigned n, sat::literal const* lits); void asserted(sat::literal lit); void propagate(); + bool can_propagate() const { return m_qhead < m_queue.size(); } void mark_relevant(euf::enode* n); void mark_relevant(sat::literal lit); @@ -139,6 +141,9 @@ namespace smt { bool is_relevant(sat::literal lit) const { return !m_enabled || m_relevant_var_ids.get(lit.var(), false); } bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); } bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); } - + + bool enabled() const { return m_enabled; } + + void add_relevant(euf::th_solver* th) { m_relevant_eh.push_back(th); } }; } From 95e26aaad9a1f0e4fe4712eeb1e8323e54550eec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 11:00:34 -0800 Subject: [PATCH 31/88] #5742 expose access to constructors/accessors/recognizers given datatype sort --- src/api/c++/z3++.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 7ac4eacdc..2c8505f27 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -701,6 +701,9 @@ namespace z3 { sort array_range() const { assert(is_array()); Z3_sort s = Z3_get_array_sort_range(ctx(), *this); check_error(); return sort(ctx(), s); } friend std::ostream & operator<<(std::ostream & out, sort const & s) { return out << Z3_sort_to_string(s.ctx(), Z3_sort(s.m_ast)); } + + func_decl_vector constructors(); + func_decl_vector recognizers(); }; /** @@ -741,6 +744,9 @@ namespace z3 { expr operator()(expr const & a1, expr const & a2, expr const & a3) const; expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const; expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; + + func_decl_vector accessors(); + }; /** @@ -3863,6 +3869,42 @@ namespace z3 { return expr_vector(*this, r); } + inline func_decl_vector sort::constructors() { + assert(is_datatype()); + func_decl_vector cs(ctx()); + unsigned n = Z3_get_datatype_sort_num_constructors(ctx(), *this); + for (unsigned i = 0; i < n; ++i) + cs.push_back(func_decl(ctx(), Z3_get_datatype_sort_constructor(ctx(), *this, i))); + return cs; + } + + inline func_decl_vector sort::recognizers() { + assert(is_datatype()); + func_decl_vector rs(ctx()); + unsigned n = Z3_get_datatype_sort_num_constructors(ctx(), *this); + for (unsigned i = 0; i < n; ++i) + rs.push_back(func_decl(ctx(), Z3_get_datatype_sort_recognizer(ctx(), *this, i))); + return rs; + } + + inline func_decl_vector func_decl::accessors() { + sort s = range(); + assert(s.is_datatype()); + unsigned n = Z3_get_datatype_sort_num_constructors(ctx(), s); + unsigned idx = 0; + for (; idx < n; ++idx) { + func_decl f(ctx(), Z3_get_datatype_sort_constructor(ctx(), s, idx)); + if (id() == f.id()) + break; + } + assert(idx < n); + n = arity(); + func_decl_vector as(ctx()); + for (unsigned i = 0; i < n; ++i) + as.push_back(func_decl(ctx(), Z3_get_datatype_sort_constructor_accessor(ctx(), s, idx, i))); + return as; + } + inline expr expr::substitute(expr_vector const& src, expr_vector const& dst) { assert(src.size() == dst.size()); From 5ed27a6c3876e83522ff85769d4b1fc1e65e86ba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 12:06:56 -0800 Subject: [PATCH 32/88] fix initialization Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_solver.cpp | 2 ++ src/sat/smt/smt_relevant.cpp | 4 +++- src/sat/smt/smt_relevant.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index ca931ce8f..d6ba945db 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -52,6 +52,7 @@ namespace euf { m_values(m) { updt_params(p); + m_relevancy.set_enabled(get_config().m_relevancy_lvl > 2); std::function disp = [&](std::ostream& out, void* j) { @@ -70,6 +71,7 @@ namespace euf { void solver::updt_params(params_ref const& p) { m_config.updt_params(p); + std::cout << get_config().m_relevancy_lvl << "\n"; } /** diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index 9d118001c..b88f204cb 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -22,7 +22,6 @@ Author: namespace smt { relevancy::relevancy(euf::solver& ctx): ctx(ctx) { - m_enabled = ctx.get_config().m_relevancy_lvl > 2; } void relevancy::relevant_eh(euf::enode* n) { @@ -73,6 +72,9 @@ namespace smt { case update::set_root: m_roots[idx] = false; break; + case update::set_qhead: + m_qhead = idx; + break; default: UNREACHABLE(); break; diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index a20ca1b44..902a005f4 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -143,6 +143,7 @@ namespace smt { bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); } bool enabled() const { return m_enabled; } + void set_enabled(bool e) { m_enabled = e; } void add_relevant(euf::th_solver* th) { m_relevant_eh.push_back(th); } }; From 743e56bda31fdd30b2d203afef2c6e42549c96d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 12:08:10 -0800 Subject: [PATCH 33/88] remove output Signed-off-by: Nikolaj Bjorner --- src/sat/smt/euf_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index d6ba945db..e90dfa32f 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -71,7 +71,6 @@ namespace euf { void solver::updt_params(params_ref const& p) { m_config.updt_params(p); - std::cout << get_config().m_relevancy_lvl << "\n"; } /** From 8ff8252e893251c4f359bb90a027b99ca6b33191 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 13:02:09 -0800 Subject: [PATCH 34/88] debug relevancy mode --- src/sat/smt/euf_relevancy.cpp | 7 +++++++ src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/euf_solver.h | 3 ++- src/sat/smt/q_ematch.cpp | 2 +- src/sat/smt/smt_relevant.cpp | 2 +- src/sat/smt/smt_relevant.h | 26 +++++++++++++++++++++----- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index a15e7bacc..e4c2c1b4d 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -73,6 +73,13 @@ namespace euf { return m_relevant_expr_ids.get(n->get_expr_id(), true); } + bool solver::is_relevant(bool_var v) const { + if (m_relevancy.enabled()) + return m_relevancy.is_relevant(v); + expr* e = bool_var2expr(v); + return !e || is_relevant(e); + } + void solver::ensure_dual_solver() { if (m_relevancy.enabled()) return; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index e90dfa32f..d8afa23ed 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -813,7 +813,7 @@ namespace euf { out << "bool-vars\n"; for (unsigned v : m_var_trail) { expr* e = m_bool_var2expr[v]; - out << v << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1) << "\n"; + out << v << (is_relevant(v)?"":"n") << ": " << e->get_id() << " " << m_solver->value(v) << " " << mk_bounded_pp(e, m, 1) << "\n"; } for (auto* e : m_solvers) e->display(out); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 2145594f1..c2a7776ef 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -257,7 +257,7 @@ namespace euf { ast_manager& get_manager() { return m; } enode* get_enode(expr* e) const { return m_egraph.find(e); } enode* bool_var2enode(sat::bool_var b) const { - expr* e = m_bool_var2expr.get(b); + expr* e = m_bool_var2expr.get(b, nullptr); return e ? get_enode(e) : nullptr; } sat::literal expr2literal(expr* e) const { return enode2literal(get_enode(e)); } @@ -394,6 +394,7 @@ namespace euf { void track_relevancy(sat::bool_var v); bool is_relevant(expr* e) const; bool is_relevant(enode* n) const; + bool is_relevant(bool_var v) const; void add_auto_relevant(sat::literal lit); void pop_relevant(unsigned n); void push_relevant(); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index a5f64f677..85287f47a 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -589,7 +589,7 @@ namespace q { return m_inst_queue.propagate() || propagated; ctx.push(value_trail(m_qhead)); ptr_buffer to_remove; - for (; m_qhead < m_clause_queue.size(); ++m_qhead) { + for (; m_qhead < m_clause_queue.size() && m.inc(); ++m_qhead) { unsigned idx = m_clause_queue[m_qhead]; clause& c = *m_clauses[idx]; binding* b = c.m_bindings; diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index b88f204cb..6a5da9df5 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -61,7 +61,7 @@ namespace smt { case update::add_clause: { sat::clause* c = m_clauses.back(); for (sat::literal lit : *c) { - SASSERT(m_occurs[lit.index()] == m_clauses.size() - 1); + SASSERT(m_occurs[lit.index()].back() == m_clauses.size() - 1); m_occurs[lit.index()].pop_back(); } m_clauses.pop_back(); diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index 902a005f4..bd35e6f72 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -19,6 +19,21 @@ Clauses are split into two parts: - Roots - Defs +The goal is to establish a labeling of literals as "relevant" such that +- the set of relevant literals satisfies Roots +- there is a set of blocked literals that can be used to satisfy the clauses in Defs + independent of their real assignment. + +The idea is that the Defs clauses are obtained from Tseitin transformation so they can be +grouped by the blocked literal that was used to introduce them. +For example, when clausifying (and a b) we have the clauses +(=> (and a b) a) +(=> (and a b) b) +(or (not a) (not b) (and a b)) +then the literal for "(and a b)" is blocked. +And recursively for clauses introduced for a, b if they use a Boolean connectives +at top level. + The state transitions are: - A literal lit is assigned: @@ -37,7 +52,7 @@ The state transitions are: - A lit is set relevant: -> - all clauses C in Defs where lit appears negatively are added to Roots + all clauses D in Defs where lit appears negatively are added to Roots - When a clause R is added to Roots: R contains a positive literal lit that is relevant @@ -49,10 +64,10 @@ The state transitions are: -> lit is set relevant -- When a clause C is added to Defs: - C contains a negative literal that is relevant +- When a clause D is added to Defs: + D contains a negative literal that is relevant -> - Add C to Roots + Add D to Roots - When an expression is set relevant: All non-relevant children above Boolean connectives are set relevant @@ -138,7 +153,8 @@ namespace smt { void mark_relevant(sat::literal lit); void merge(euf::enode* n1, euf::enode* n2); - bool is_relevant(sat::literal lit) const { return !m_enabled || m_relevant_var_ids.get(lit.var(), false); } + bool is_relevant(sat::bool_var v) const { return !m_enabled || m_relevant_var_ids.get(v, false); } + bool is_relevant(sat::literal lit) const { return is_relevant(lit.var()); } bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); } bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); } From 1706f77b9ec4bf7a333dd2b720f6a4d5db5c9d38 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 28 Dec 2021 18:53:37 -0800 Subject: [PATCH 35/88] optimize propagation to only blocked literals --- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/smt_relevant.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index d8afa23ed..b8fbc5bd9 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -479,7 +479,7 @@ namespace euf { return sat::check_result::CR_CONTINUE; if (!init_relevancy()) - give_up = true; + give_up = true; unsigned num_nodes = m_egraph.num_nodes(); auto apply_solver = [&](th_solver* e) { diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index 6a5da9df5..574ba0b42 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -215,6 +215,9 @@ namespace smt { void relevancy::propagate_relevant(sat::literal lit) { relevant_eh(lit); + euf::enode* n = ctx.bool_var2enode(lit.var()); + if (n && !ctx.get_si().is_bool_op(n->get_expr())) + return; for (auto idx : occurs(~lit)) { if (m_roots[idx]) continue; From f215b18e0ec8e6e537cb3320aa92b0d92d161730 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Dec 2021 13:03:43 -0800 Subject: [PATCH 36/88] change registration mode for relevant_eh --- src/sat/smt/array_axioms.cpp | 8 ++++- src/sat/smt/array_internalize.cpp | 55 ++++++++++++++++++------------- src/sat/smt/array_solver.h | 1 + src/sat/smt/euf_solver.cpp | 10 ++++++ src/sat/smt/euf_solver.h | 1 + src/sat/smt/q_ematch.cpp | 7 ++-- src/sat/smt/smt_relevant.cpp | 3 +- src/sat/smt/smt_relevant.h | 3 -- 8 files changed, 55 insertions(+), 33 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index d362dacb6..c0ab2ecbf 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -539,6 +539,8 @@ namespace array { if (!d.m_prop_upward) continue; euf::enode* n = var2enode(v); + if (!ctx.is_relevant(n)) + continue; if (add_as_array_eqs(n)) change = true; bool has_default = false; @@ -567,6 +569,8 @@ namespace array { return false; for (unsigned i = 0; i < ctx.get_egraph().enodes_of(f).size(); ++i) { euf::enode* p = ctx.get_egraph().enodes_of(f)[i]; + if (!ctx.is_relevant(p)) + continue; expr_ref_vector select(m); select.push_back(n->get_expr()); for (expr* arg : *to_app(p->get_expr())) @@ -615,7 +619,9 @@ namespace array { euf::enode * n = var2enode(i); if (!is_array(n)) - continue; + continue; + if (!ctx.is_relevant(n)) + continue; euf::enode * r = n->get_root(); if (r->is_marked1()) continue; diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index aa94f12a7..1076acc30 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -124,40 +124,49 @@ namespace array { mk_var(n); for (auto* arg : euf::enode_args(n)) ensure_var(arg); - switch (a->get_decl_kind()) { - case OP_STORE: - internalize_store(n); + if (ctx.is_relevant(n)) + relevant_eh(n); + return true; + } + + void solver::relevant_eh(euf::enode* n) { + if (!is_app(n->get_expr())) + return; + if (n->get_decl()->get_family_id() != a.get_family_id()) + return; + switch (n->get_decl()->get_decl_kind()) { + case OP_STORE: + internalize_store(n); break; - case OP_SELECT: - internalize_select(n); + case OP_SELECT: + internalize_select(n); break; case OP_AS_ARRAY: - case OP_CONST_ARRAY: - internalize_lambda(n); + case OP_CONST_ARRAY: + internalize_lambda(n); break; - case OP_ARRAY_EXT: - internalize_ext(n); + case OP_ARRAY_EXT: + internalize_ext(n); break; - case OP_ARRAY_DEFAULT: - internalize_default(n); + case OP_ARRAY_DEFAULT: + internalize_default(n); break; - case OP_ARRAY_MAP: - internalize_map(n); + case OP_ARRAY_MAP: + internalize_map(n); break; - case OP_SET_UNION: - case OP_SET_INTERSECT: - case OP_SET_DIFFERENCE: - case OP_SET_COMPLEMENT: - case OP_SET_SUBSET: - case OP_SET_HAS_SIZE: - case OP_SET_CARD: - ctx.unhandled_function(a->get_decl()); + case OP_SET_UNION: + case OP_SET_INTERSECT: + case OP_SET_DIFFERENCE: + case OP_SET_COMPLEMENT: + case OP_SET_SUBSET: + case OP_SET_HAS_SIZE: + case OP_SET_CARD: + ctx.unhandled_function(n->get_decl()); break; default: UNREACHABLE(); - break; + break; } - return true; } /** diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 0c0fc82d6..8f9bd31f8 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -264,6 +264,7 @@ namespace array { void apply_sort_cnstr(euf::enode* n, sort* s) override; bool is_shared(theory_var v) const override; bool enable_self_propagate() const override { return true; } + void relevant_eh(euf::enode* n) override; void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2); void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index b8fbc5bd9..5c94d21ba 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -739,6 +739,16 @@ namespace euf { } } + void solver::relevant_eh(euf::enode* n) { + if (m_qsolver) + m_qsolver->relevant_eh(n); + for (auto thv : enode_th_vars(n)) { + auto* th = m_id2solver.get(thv.get_id(), nullptr); + if (th && th != m_qsolver) + th->relevant_eh(n); + } + } + void solver::pre_simplify() { for (auto* e : m_solvers) e->pre_simplify(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index c2a7776ef..1ff072b03 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -398,6 +398,7 @@ namespace euf { void add_auto_relevant(sat::literal lit); void pop_relevant(unsigned n); void push_relevant(); + void relevant_eh(euf::enode* n); smt::relevancy& relevancy() { return m_relevancy; } // model construction diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 85287f47a..827405f85 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -70,15 +70,14 @@ namespace q { }; ctx.get_egraph().set_on_merge(_on_merge); - if (ctx.relevancy().enabled()) + if (!ctx.relevancy().enabled()) ctx.get_egraph().set_on_make(_on_make); - else - ctx.relevancy().add_relevant(&s); m_mam = mam::mk(ctx, *this); } void ematch::relevant_eh(euf::enode* n) { - m_mam->add_node(n, false); + if (ctx.relevancy().enabled()) + m_mam->add_node(n, false); } void ematch::ensure_ground_enodes(expr* e) { diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index 574ba0b42..14d164952 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -26,8 +26,7 @@ namespace smt { void relevancy::relevant_eh(euf::enode* n) { SASSERT(is_relevant(n)); - for (auto* th : m_relevant_eh) - th->relevant_eh(n); + ctx.relevant_eh(n); } void relevancy::relevant_eh(sat::literal lit) { diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index bd35e6f72..9e8ba00c3 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -120,7 +120,6 @@ namespace smt { vector m_occurs; // where do literals occur unsigned m_qhead = 0; // queue head for relevancy svector> m_queue; // propagation queue for relevancy - ptr_vector m_relevant_eh; // callbacks during propagation void relevant_eh(euf::enode* n); @@ -160,7 +159,5 @@ namespace smt { bool enabled() const { return m_enabled; } void set_enabled(bool e) { m_enabled = e; } - - void add_relevant(euf::th_solver* th) { m_relevant_eh.push_back(th); } }; } From 69b4392210562d8be06d53a9c3ca77cc1a0776dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Dec 2021 13:04:31 -0800 Subject: [PATCH 37/88] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_ematch.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 827405f85..8d3bc5995 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -66,8 +66,7 @@ namespace q { }; std::function _on_make = [&](euf::enode* n) { - relevant_eh(n); - + m_mam->add_node(n, false); }; ctx.get_egraph().set_on_merge(_on_merge); if (!ctx.relevancy().enabled()) From a90b66134d74fa2e6b36968955d306902ccc3cc6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Dec 2021 13:42:11 -0800 Subject: [PATCH 38/88] make roots uniform for theory lemmas --- src/sat/smt/array_internalize.cpp | 2 +- src/sat/smt/bv_internalize.cpp | 5 ----- src/sat/smt/euf_internalize.cpp | 18 ++++++------------ src/sat/smt/q_mbi.cpp | 1 - src/sat/smt/q_solver.cpp | 3 --- src/sat/smt/sat_th.cpp | 26 +++++++++++--------------- src/sat/smt/sat_th.h | 3 ++- 7 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 1076acc30..8fef8b316 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -124,7 +124,7 @@ namespace array { mk_var(n); for (auto* arg : euf::enode_args(n)) ensure_var(arg); - if (ctx.is_relevant(n)) + if (ctx.is_relevant(n) || !ctx.relevancy().enabled()) relevant_eh(n); return true; } diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 2fec734df..77115b441 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -427,7 +427,6 @@ namespace bv { expr_ref sum(m_autil.mk_add(sz, args.data()), m); sat::literal lit = eq_internalize(n, sum); add_unit(lit); - ctx.add_root(lit); } void solver::internalize_int2bv(app* n) { @@ -457,7 +456,6 @@ namespace bv { rhs = m_autil.mk_mod(e, m_autil.mk_int(mod)); sat::literal eq_lit = eq_internalize(lhs, rhs); add_unit(eq_lit); - ctx.add_root(eq_lit); expr_ref_vector n_bits(m); get_bits(n_enode, n_bits); @@ -470,7 +468,6 @@ namespace bv { lhs = n_bits.get(i); eq_lit = eq_internalize(lhs, rhs); add_unit(eq_lit); - ctx.add_root(eq_lit); } } @@ -536,7 +533,6 @@ namespace bv { if (p.hi_div0()) { eq_lit = eq_internalize(n, ibin(arg1, arg2)); add_unit(eq_lit); - ctx.add_root(eq_lit); } else { unsigned sz = bv.get_bv_size(n); @@ -654,7 +650,6 @@ namespace bv { mk_bits(get_th_var(e)); sat::literal eq_lit = eq_internalize(e, r); add_unit(eq_lit); - ctx.add_root(eq_lit); } void solver::internalize_bit2bool(app* n) { diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 90a268661..6079002a5 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -162,10 +162,8 @@ namespace euf { sat::literal lit2 = literal(v, false); s().mk_clause(~lit, lit2, sat::status::th(m_is_redundant, m.get_basic_family_id())); s().mk_clause(lit, ~lit2, sat::status::th(m_is_redundant, m.get_basic_family_id())); - if (relevancy_enabled()) { - add_aux(~lit, lit2); - add_aux(lit, ~lit2); - } + add_aux(~lit, lit2); + add_aux(lit, ~lit2); lit = lit2; } @@ -225,8 +223,7 @@ namespace euf { } } s().mk_clause(lits, st); - if (relevancy_enabled()) - add_root(lits); + add_root(lits); } else { // g(f(x_i)) = x_i @@ -251,8 +248,7 @@ namespace euf { expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.data(), 2), m); sat::literal lit = si.internalize(at_least2, m_is_redundant); s().mk_clause(1, &lit, st); - if (relevancy_enabled()) - add_root(1, &lit); + add_root(1, &lit); } } @@ -269,8 +265,7 @@ namespace euf { expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr()); sat::literal lit = ~mk_literal(eq); s().add_clause(1, &lit, st); - if (relevancy_enabled()) - add_root(1, &lit); + add_root(1, &lit); } } } @@ -288,8 +283,7 @@ namespace euf { expr_ref eq = mk_eq(fapp, fresh); sat::literal lit = mk_literal(eq); s().add_clause(1, &lit, st); - if (relevancy_enabled()) - add_root(1, &lit); + add_root(1, &lit); } } } diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index a7a2d67d7..20e65b8d6 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -71,7 +71,6 @@ namespace q { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ctx.mk_literal(fml); m_qs.add_clause(~qlit, ~lit); - ctx.add_root(~qlit, ~lit); } m_instantiations.reset(); return result; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index 148383c2b..6ef4012af 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -44,19 +44,16 @@ namespace q { if (l.sign() == is_forall(e)) { sat::literal lit = skolemize(q); add_clause(~l, lit); - ctx.add_root(~l, lit); } else if (expand(q)) { for (expr* e : m_expanded) { sat::literal lit = ctx.internalize(e, l.sign(), false, false); add_clause(~l, lit); - ctx.add_root(~l, lit); } } else if (is_ground(q->get_expr())) { auto lit = ctx.internalize(q->get_expr(), l.sign(), false, false); add_clause(~l, lit); - ctx.add_root(~l, lit); } else { ctx.push_vec(m_universal, l); diff --git a/src/sat/smt/sat_th.cpp b/src/sat/smt/sat_th.cpp index 06efccaf0..f72ff601a 100644 --- a/src/sat/smt/sat_th.cpp +++ b/src/sat/smt/sat_th.cpp @@ -132,6 +132,7 @@ namespace euf { bool th_euf_solver::add_unit(sat::literal lit) { bool was_true = is_true(lit); ctx.s().add_clause(1, &lit, mk_status()); + ctx.add_root(lit); return !was_true; } @@ -143,32 +144,27 @@ namespace euf { return is_new; } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b) { - bool was_true = is_true(a, b); + bool th_euf_solver::add_clause(sat::literal a, sat::literal b) { sat::literal lits[2] = { a, b }; - ctx.s().add_clause(2, lits, mk_status()); - return !was_true; + return add_clause(2, lits); } - bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) { - bool was_true = is_true(a, b, c); + bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; - ctx.s().add_clause(3, lits, mk_status()); - return !was_true; + return add_clause(3, lits); } bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d) { - bool was_true = is_true(a, b, c, d); sat::literal lits[4] = { a, b, c, d }; - ctx.s().add_clause(4, lits, mk_status()); - return !was_true; + return add_clause(4, lits); } - bool th_euf_solver::add_clause(sat::literal_vector const& lits) { + bool th_euf_solver::add_clause(unsigned n, sat::literal* lits) { bool was_true = false; - for (auto lit : lits) - was_true |= is_true(lit); - s().add_clause(lits.size(), lits.data(), mk_status()); + for (unsigned i = 0; i < n; ++i) + was_true |= is_true(lits[i]); + ctx.add_root(n, lits); + s().add_clause(n, lits, mk_status()); return !was_true; } diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index fecb745c5..16138441c 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -141,7 +141,8 @@ namespace euf { bool add_clause(sat::literal a, sat::literal b); bool add_clause(sat::literal a, sat::literal b, sat::literal c); bool add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d); - bool add_clause(sat::literal_vector const& lits); + bool add_clause(sat::literal_vector const& lits) { return add_clause(lits.size(), lits.data()); } + bool add_clause(unsigned n, sat::literal* lits); void add_equiv(sat::literal a, sat::literal b); void add_equiv_and(sat::literal a, sat::literal_vector const& bs); From b87b464e6954d56e12ab61f3d457307b4800cc61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 Dec 2021 17:57:28 -0800 Subject: [PATCH 39/88] set relevancy flag on enode --- src/ast/euf/euf_egraph.cpp | 13 +++++++++++++ src/ast/euf/euf_egraph.h | 8 +++++++- src/ast/euf/euf_enode.h | 3 +++ src/sat/smt/bv_delay_internalize.cpp | 5 ++++- src/sat/smt/euf_relevancy.cpp | 9 +-------- src/sat/smt/euf_solver.h | 1 - src/sat/smt/q_mbi.cpp | 2 +- src/sat/smt/q_model_fixer.cpp | 2 +- src/sat/smt/smt_relevant.cpp | 14 +++++++------- src/sat/smt/smt_relevant.h | 8 +++----- 10 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index f1e51ee1d..4a752781c 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -25,6 +25,8 @@ namespace euf { enode* egraph::mk_enode(expr* f, unsigned generation, unsigned num_args, enode * const* args) { enode* n = enode::mk(m_region, f, generation, num_args, args); + if (m_default_relevant) + n->set_relevant(true); m_nodes.push_back(n); m_exprs.push_back(f); if (is_app(f) && num_args > 0) { @@ -269,6 +271,13 @@ namespace euf { } } + void egraph::set_relevant(enode* n) { + if (n->is_relevant()) + return; + n->set_relevant(true); + m_updates.push_back(update_record(n, update_record::set_relevant())); + } + void egraph::toggle_merge_enabled(enode* n, bool backtracking) { bool enable_merge = !n->merge_enabled(); n->set_merge_enabled(enable_merge); @@ -380,6 +389,10 @@ namespace euf { case update_record::tag_t::is_lbl_set: p.r1->m_lbls.set(p.m_lbls); break; + case update_record::tag_t::is_set_relevant: + SASSERT(p.r1->is_relevant()); + p.r1->set_relevant(false); + break; case update_record::tag_t::is_update_children: for (unsigned i = 0; i < p.r1->num_args(); ++i) { SASSERT(p.r1->m_args[i]->get_root()->m_parents.back() == p.r1); diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index ef70fafd5..a91dbf4a4 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -106,10 +106,11 @@ namespace euf { struct lbl_hash {}; struct lbl_set {}; struct update_children {}; + struct set_relevant {}; enum class tag_t { is_set_parent, is_add_node, is_toggle_merge, is_update_children, is_add_th_var, is_replace_th_var, is_new_lit, is_new_th_eq, is_lbl_hash, is_new_th_eq_qhead, is_new_lits_qhead, - is_inconsistent, is_value_assignment, is_lbl_set }; + is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant }; tag_t tag; enode* r1; enode* n1; @@ -152,6 +153,8 @@ namespace euf { tag(tag_t::is_lbl_set), r1(n), n1(nullptr), m_lbls(n->m_lbls.get()) {} update_record(enode* n, update_children) : tag(tag_t::is_update_children), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} + update_record(enode* n, set_relevant) : + tag(tag_t::is_set_relevant), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {} }; ast_manager& m; svector m_to_merge; @@ -182,6 +185,7 @@ namespace euf { enode_vector m_todo; stats m_stats; bool m_uses_congruence = false; + bool m_default_relevant = true; std::vector> m_on_merge; std::function m_on_make; std::function m_used_eq; @@ -293,6 +297,8 @@ namespace euf { void set_merge_enabled(enode* n, bool enable_merge); void set_value(enode* n, lbool value); void set_bool_var(enode* n, unsigned v) { n->set_bool_var(v); } + void set_relevant(enode* n); + void set_default_relevant(bool b) { m_default_relevant = b; } void set_on_merge(std::function& on_merge) { m_on_merge.push_back(on_merge); } void set_on_make(std::function& on_make) { m_on_make = on_make; } diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index 8498c9790..9cd812a9a 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -49,6 +49,7 @@ namespace euf { bool m_interpreted = false; bool m_merge_enabled = true; bool m_is_equality = false; // Does the expression represent an equality + bool m_is_relevant = false; lbool m_value = l_undef; // Assignment by SAT solver for Boolean node sat::bool_var m_bool_var = sat::null_bool_var; // SAT solver variable associated with Boolean node unsigned m_class_size = 1; // Size of the equivalence class if the enode is the root. @@ -145,6 +146,8 @@ namespace euf { unsigned num_parents() const { return m_parents.size(); } bool interpreted() const { return m_interpreted; } bool is_equality() const { return m_is_equality; } + bool is_relevant() const { return m_is_relevant; } + void set_relevant(bool b) { m_is_relevant = b; } lbool value() const { return m_value; } bool value_conflict() const { return value() != l_undef && get_root()->value() != l_undef && value() != get_root()->value(); } sat::bool_var bool_var() const { return m_bool_var; } diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index ca4841656..144ed105d 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -21,7 +21,10 @@ Author: namespace bv { bool solver::check_delay_internalized(expr* e) { - if (!ctx.is_relevant(e)) + euf::enode* n = expr2enode(e); + if (!n) + return true; + if (!ctx.is_relevant(n)) return true; if (get_internalize_mode(e) != internalize_mode::delay_i) return true; diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index e4c2c1b4d..4851f4a04 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -31,7 +31,6 @@ namespace euf { return; for (; m_auto_relevant_scopes > 0; --m_auto_relevant_scopes) m_auto_relevant_lim.push_back(m_auto_relevant.size()); - // std::cout << "add-auto " << e->get_id() << " " << mk_bounded_pp(e, m) << "\n"; expr* e = bool_var2expr(lit.var()); m_auto_relevant.push_back(e); } @@ -61,12 +60,6 @@ namespace euf { ++m_auto_relevant_scopes; } - bool solver::is_relevant(expr* e) const { - if (m_relevancy.enabled()) - return m_relevancy.is_relevant(e); - return m_relevant_expr_ids.get(e->get_id(), true); - } - bool solver::is_relevant(enode* n) const { if (m_relevancy.enabled()) return m_relevancy.is_relevant(n); @@ -76,7 +69,7 @@ namespace euf { bool solver::is_relevant(bool_var v) const { if (m_relevancy.enabled()) return m_relevancy.is_relevant(v); - expr* e = bool_var2expr(v); + auto* e = bool_var2enode(v); return !e || is_relevant(e); } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 1ff072b03..b3cdf99bc 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -392,7 +392,6 @@ namespace euf { void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); } void add_aux(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; add_aux(3, lits); } void track_relevancy(sat::bool_var v); - bool is_relevant(expr* e) const; bool is_relevant(enode* n) const; bool is_relevant(bool_var v) const; void add_auto_relevant(sat::literal lit); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 20e65b8d6..000937700 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -51,7 +51,7 @@ namespace q { m_instantiations.reset(); for (sat::literal lit : m_qs.m_universal) { quantifier* q = to_quantifier(ctx.bool_var2expr(lit.var())); - if (!ctx.is_relevant(q)) + if (!ctx.is_relevant(lit.var())) continue; init_model(); switch (check_forall(q)) { diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index 3339daf2d..a87bf3397 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -66,7 +66,7 @@ namespace q { ptr_vector univ; for (sat::literal lit : m_qs.universal()) { quantifier* q = to_quantifier(ctx.bool_var2expr(lit.var())); - if (ctx.is_relevant(q)) + if (ctx.is_relevant(lit.var())) univ.push_back(q); } if (univ.empty()) diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index 14d164952..d7f35b563 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -49,10 +49,6 @@ namespace smt { for (unsigned i = m_trail.size(); i-- > sz; ) { auto [u, idx] = m_trail[i]; switch (u) { - case update::relevant_expr: - m_relevant_expr_ids[idx] = false; - m_queue.pop_back(); - break; case update::relevant_var: m_relevant_var_ids[idx] = false; m_queue.pop_back(); @@ -191,10 +187,9 @@ namespace smt { } void relevancy::set_relevant(euf::enode* n) { - if (is_relevant(n)) + if (n->is_relevant()) return; - m_relevant_expr_ids.setx(n->get_expr_id(), true, false); - m_trail.push_back(std::make_pair(update::relevant_expr, n->get_expr_id())); + ctx.get_egraph().set_relevant(n); m_queue.push_back(std::make_pair(sat::null_literal, n)); } @@ -247,4 +242,9 @@ namespace smt { mark_relevant(arg); } + void relevancy::set_enabled(bool e) { + m_enabled = e; + ctx.get_egraph().set_default_relevant(!e); + } + } diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index 9e8ba00c3..73f04cf40 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -106,13 +106,12 @@ namespace smt { class relevancy { euf::solver& ctx; - enum class update { relevant_expr, relevant_var, add_clause, set_root, set_qhead }; + enum class update { relevant_var, add_clause, set_root, set_qhead }; bool m_enabled = false; svector> m_trail; unsigned_vector m_lim; unsigned m_num_scopes = 0; - bool_vector m_relevant_expr_ids; // identifiers of relevant expressions bool_vector m_relevant_var_ids; // identifiers of relevant Boolean variables sat::clause_allocator m_alloc; sat::clause_vector m_clauses; // clauses @@ -154,10 +153,9 @@ namespace smt { bool is_relevant(sat::bool_var v) const { return !m_enabled || m_relevant_var_ids.get(v, false); } bool is_relevant(sat::literal lit) const { return is_relevant(lit.var()); } - bool is_relevant(euf::enode* n) const { return !m_enabled || m_relevant_expr_ids.get(n->get_expr_id(), false); } - bool is_relevant(expr* e) const { return !m_enabled || m_relevant_expr_ids.get(e->get_id(), false); } + bool is_relevant(euf::enode* n) const { return !m_enabled || n->is_relevant(); } bool enabled() const { return m_enabled; } - void set_enabled(bool e) { m_enabled = e; } + void set_enabled(bool e); }; } From e8833f4dacbdd34049624f120e1fad2f3f13d2cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 30 Dec 2021 17:07:14 -0800 Subject: [PATCH 40/88] working on relevancy=3 --- src/ast/euf/euf_egraph.cpp | 2 ++ src/sat/smt/arith_solver.cpp | 1 + src/sat/smt/array_axioms.cpp | 47 +++++++++------------------- src/sat/smt/array_internalize.cpp | 3 +- src/sat/smt/array_solver.h | 1 - src/sat/smt/bv_delay_internalize.cpp | 2 +- src/sat/smt/euf_internalize.cpp | 4 +-- src/sat/smt/euf_model.cpp | 5 ++- src/sat/smt/euf_relevancy.cpp | 2 +- src/sat/smt/euf_solver.cpp | 2 +- src/sat/smt/euf_solver.h | 4 +-- src/sat/smt/pb_solver.cpp | 2 +- src/sat/smt/recfun_solver.cpp | 4 +-- src/sat/smt/smt_relevant.cpp | 43 +++++++++++++++++-------- src/sat/smt/smt_relevant.h | 5 ++- 15 files changed, 65 insertions(+), 62 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 4a752781c..f5249ab31 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -767,6 +767,8 @@ namespace euf { } std::ostream& egraph::display(std::ostream& out, unsigned max_args, enode* n) const { + if (!n->is_relevant()) + out << "n"; out << "#" << n->get_expr_id() << " := "; expr* f = n->get_expr(); if (is_app(f)) diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index da68691c7..19be6d9d5 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -953,6 +953,7 @@ namespace arith { if (n1->get_root() == n2->get_root()) continue; literal eq = eq_internalize(n1, n2); + ctx.mark_relevant(eq); if (s().value(eq) != l_true) return true; } diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index c0ab2ecbf..62f111ea6 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -57,8 +57,6 @@ namespace array { bool solver::assert_axiom(unsigned idx) { axiom_record& r = m_axiom_trail[idx]; - if (!is_relevant(r)) - return false; switch (r.m_kind) { case axiom_record::kind_t::is_store: return assert_store_axiom(to_app(r.n->get_expr())); @@ -92,29 +90,6 @@ namespace array { return false; } - - bool solver::is_relevant(axiom_record const& r) const { - return true; -#if 0 - // relevancy propagation is currently incomplete on terms - - expr* child = r.n->get_expr(); - switch (r.m_kind) { - case axiom_record::kind_t::is_select: { - app* select = r.select->get_app(); - for (unsigned i = 1; i < select->get_num_args(); ++i) - if (!ctx.is_relevant(select->get_arg(i))) - return false; - return ctx.is_relevant(child); - } - case axiom_record::kind_t::is_default: - return ctx.is_relevant(child); - default: - return true; - } -#endif - } - bool solver::assert_select(unsigned idx, axiom_record& r) { expr* child = r.n->get_expr(); app* select = r.select->get_app(); @@ -215,10 +190,17 @@ namespace array { return new_prop; sat::literal sel_eq = sat::null_literal; + auto ensure_relevant = [&](sat::literal lit) { + if (ctx.is_relevant(lit)) + return; + new_prop = true; + ctx.mark_relevant(lit); + }; auto init_sel_eq = [&]() { if (sel_eq != sat::null_literal) return true; sel_eq = mk_literal(sel_eq_e); + ensure_relevant(sel_eq); return s().value(sel_eq) != l_true; }; @@ -235,6 +217,7 @@ namespace array { break; } sat::literal idx_eq = eq_internalize(idx1, idx2); + ensure_relevant(idx_eq); if (s().value(idx_eq) == l_true) continue; if (s().value(idx_eq) == l_undef) @@ -598,13 +581,12 @@ namespace array { expr* e2 = var2expr(v2); if (e1->get_sort() != e2->get_sort()) continue; - if (must_have_different_model_values(v1, v2)) { - continue; - } - if (ctx.get_egraph().are_diseq(var2enode(v1), var2enode(v2))) { - continue; - } + if (must_have_different_model_values(v1, v2)) + continue; + if (ctx.get_egraph().are_diseq(var2enode(v1), var2enode(v2))) + continue; sat::literal lit = eq_internalize(e1, e2); + ctx.mark_relevant(lit); if (s().value(lit) == l_undef) prop = true; } @@ -616,8 +598,7 @@ namespace array { ptr_buffer to_unmark; unsigned num_vars = get_num_vars(); for (unsigned i = 0; i < num_vars; i++) { - euf::enode * n = var2enode(i); - + euf::enode * n = var2enode(i); if (!is_array(n)) continue; if (!ctx.is_relevant(n)) diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 8fef8b316..b74d46fe6 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -58,6 +58,7 @@ namespace array { } void solver::internalize_store(euf::enode* n) { + //std::cout << "store th-var " << n->get_th_var(get_id()) << "\n"; add_parent_lambda(n->get_arg(0)->get_th_var(get_id()), n); push_axiom(store_axiom(n)); add_lambda(n->get_th_var(get_id()), n); @@ -71,7 +72,7 @@ namespace array { } push_axiom(default_axiom(n)); add_lambda(n->get_th_var(get_id()), n); - SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); + //SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); } void solver::internalize_lambda(euf::enode* n) { diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 8f9bd31f8..74788254b 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -157,7 +157,6 @@ namespace array { bool assert_axiom(unsigned idx); bool assert_select(unsigned idx, axiom_record & r); bool assert_default(axiom_record & r); - bool is_relevant(axiom_record const& r) const; void set_applied(unsigned idx) { m_axiom_trail[idx].set_applied(); } bool is_applied(unsigned idx) const { return m_axiom_trail[idx].is_applied(); } bool is_delayed(unsigned idx) const { return m_axiom_trail[idx].is_delayed(); } diff --git a/src/sat/smt/bv_delay_internalize.cpp b/src/sat/smt/bv_delay_internalize.cpp index 144ed105d..6ad10c53a 100644 --- a/src/sat/smt/bv_delay_internalize.cpp +++ b/src/sat/smt/bv_delay_internalize.cpp @@ -250,7 +250,7 @@ namespace bv { return; expr_ref tmp = literal2expr(bits.back()); for (unsigned i = bits.size() - 1; i-- > 0; ) { - auto b = bits[i]; + sat::literal b = bits[i]; tmp = m.mk_or(literal2expr(b), tmp); xs.push_back(tmp); } diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 6079002a5..68f2295a2 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -248,7 +248,7 @@ namespace euf { expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.data(), 2), m); sat::literal lit = si.internalize(at_least2, m_is_redundant); s().mk_clause(1, &lit, st); - add_root(1, &lit); + add_root(lit); } } @@ -351,7 +351,7 @@ namespace euf { // contains a parent application. family_id th_id = m.get_basic_family_id(); - for (auto p : euf::enode_th_vars(n)) { + for (auto const& p : euf::enode_th_vars(n)) { family_id id = p.get_id(); if (m.get_basic_family_id() != id) { if (th_id != m.get_basic_family_id()) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index ea5bfe274..ded947da3 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -271,6 +271,8 @@ namespace euf { void solver::display_validation_failure(std::ostream& out, model& mdl, enode* n) { out << "Failed to validate " << n->bool_var() << " " << bpp(n) << " " << mdl(n->get_expr()) << "\n"; + s().display(out); + return; euf::enode_vector nodes; nodes.push_back(n); for (unsigned i = 0; i < nodes.size(); ++i) { @@ -289,7 +291,6 @@ namespace euf { for (euf::enode* r : nodes) r->unmark1(); out << mdl << "\n"; - s().display(out); } void solver::validate_model(model& mdl) { @@ -322,6 +323,8 @@ namespace euf { IF_VERBOSE(0, display_validation_failure(verbose_stream(), mdl, n);); CTRACE("euf", first, display_validation_failure(tout, mdl, n);); (void)first; + first = false; + return; exit(1); first = false; } diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 4851f4a04..07960c584 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -22,7 +22,7 @@ Author: namespace euf { - void solver::add_auto_relevant(sat::literal lit) { + void solver::mark_relevant(sat::literal lit) { if (m_relevancy.enabled()) { m_relevancy.mark_relevant(lit); return; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 5c94d21ba..b8bd601e3 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -193,7 +193,7 @@ namespace euf { } void solver::propagate(literal lit, ext_justification_idx idx) { - add_auto_relevant(lit); + mark_relevant(lit); s().assign(lit, sat::justification::mk_ext_justification(s().scope_lvl(), idx)); } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index b3cdf99bc..dc11637b8 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -385,7 +385,6 @@ namespace euf { void add_root(unsigned n, sat::literal const* lits); void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } - void add_root(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_root(2, lits); } void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } void add_aux(unsigned n, sat::literal const* lits); void add_aux(sat::literal a) { sat::literal lits[1] = { a }; add_aux(1, lits); } @@ -394,7 +393,8 @@ namespace euf { void track_relevancy(sat::bool_var v); bool is_relevant(enode* n) const; bool is_relevant(bool_var v) const; - void add_auto_relevant(sat::literal lit); + bool is_relevant(sat::literal lit) const { return is_relevant(lit.var()); } + void mark_relevant(sat::literal lit); void pop_relevant(unsigned n); void push_relevant(); void relevant_eh(euf::enode* n); diff --git a/src/sat/smt/pb_solver.cpp b/src/sat/smt/pb_solver.cpp index 33fd1c48d..0eebd5247 100644 --- a/src/sat/smt/pb_solver.cpp +++ b/src/sat/smt/pb_solver.cpp @@ -2006,7 +2006,7 @@ namespace pb { s().pop_to_base_level(); if (s().inconsistent()) return; - unsigned trail_sz, count = 0; + unsigned trail_sz = 0, count = 0; do { trail_sz = s().init_trail_size(); m_simplify_change = false; diff --git a/src/sat/smt/recfun_solver.cpp b/src/sat/smt/recfun_solver.cpp index be7322a75..b908297ad 100644 --- a/src/sat/smt/recfun_solver.cpp +++ b/src/sat/smt/recfun_solver.cpp @@ -68,8 +68,8 @@ namespace recfun { TRACEFN("case expansion " << e); SASSERT(e.m_def->is_fun_macro()); auto & vars = e.m_def->get_vars(); - auto lhs = e.m_lhs; - auto rhs = apply_args(vars, e.m_args, e.m_def->get_rhs()); + app_ref lhs = e.m_lhs; + expr_ref rhs = apply_args(vars, e.m_args, e.m_def->get_rhs()); unsigned generation = std::max(ctx.get_max_generation(lhs), ctx.get_max_generation(rhs)); euf::solver::scoped_generation _sgen(ctx, generation + 1); auto eq = eq_internalize(lhs, rhs); diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index d7f35b563..1f57dc20a 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -30,9 +30,17 @@ namespace smt { } void relevancy::relevant_eh(sat::literal lit) { - SASSERT(ctx.s().value(lit) == l_true); SASSERT(is_relevant(lit)); - ctx.asserted(lit); + switch (ctx.s().value(lit)) { + case l_true: + ctx.asserted(lit); + break; + case l_false: + ctx.asserted(~lit); + break; + default: + break; + } } void relevancy::pop(unsigned n) { @@ -53,6 +61,9 @@ namespace smt { m_relevant_var_ids[idx] = false; m_queue.pop_back(); break; + case update::relevant_node: + m_queue.pop_back(); + break; case update::add_clause: { sat::clause* c = m_clauses.back(); for (sat::literal lit : *c) { @@ -182,14 +193,7 @@ namespace smt { return; if (ctx.get_si().is_bool_op(n->get_expr())) return; - for (euf::enode* sib : euf::enode_class(n)) - set_relevant(sib); - } - - void relevancy::set_relevant(euf::enode* n) { - if (n->is_relevant()) - return; - ctx.get_egraph().set_relevant(n); + m_trail.push_back(std::make_pair(update::relevant_node, 0)); m_queue.push_back(std::make_pair(sat::null_literal, n)); } @@ -237,9 +241,22 @@ namespace smt { } void relevancy::propagate_relevant(euf::enode* n) { - relevant_eh(n); - for (euf::enode* arg : euf::enode_args(n)) - mark_relevant(arg); + m_stack.push_back(n); + while (!m_stack.empty()) { + n = m_stack.back(); + unsigned sz = m_stack.size(); + for (euf::enode* arg : euf::enode_args(n)) + if (!arg->is_relevant()) + m_stack.push_back(arg); + if (sz == m_stack.size()) { + ctx.get_egraph().set_relevant(n); + relevant_eh(n); + for (euf::enode* sib : euf::enode_class(n)) + if (!sib->is_relevant()) + mark_relevant(sib); + m_stack.pop_back(); + } + } } void relevancy::set_enabled(bool e) { diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index 73f04cf40..fbef05b78 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -106,7 +106,7 @@ namespace smt { class relevancy { euf::solver& ctx; - enum class update { relevant_var, add_clause, set_root, set_qhead }; + enum class update { relevant_var, relevant_node, add_clause, set_root, set_qhead }; bool m_enabled = false; svector> m_trail; @@ -119,6 +119,7 @@ namespace smt { vector m_occurs; // where do literals occur unsigned m_qhead = 0; // queue head for relevancy svector> m_queue; // propagation queue for relevancy + euf::enode_vector m_stack; // callbacks during propagation void relevant_eh(euf::enode* n); @@ -133,8 +134,6 @@ namespace smt { void propagate_relevant(euf::enode* n); - void set_relevant(euf::enode* n); - public: relevancy(euf::solver& ctx); From fc77345bec16c1aa622201af6c4d088ed5886c2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 30 Dec 2021 19:11:14 -0800 Subject: [PATCH 41/88] breaking change. Enforce append semantics everywhere for parameter updates #5744 Replace semantics doesn't work with assumptions made elsewhere in code. The remedy is to apply append (override) semantics for parameter changes. --- src/api/api_datalog.cpp | 2 +- src/ast/rewriter/th_rewriter.cpp | 4 ++-- src/cmd_context/extra_cmds/dbg_cmds.cpp | 4 ++-- src/math/subpaving/tactic/subpaving_tactic.cpp | 4 ++-- src/muz/fp/horn_tactic.cpp | 4 ++-- src/nlsat/tactic/nlsat_tactic.cpp | 6 +++--- src/params/context_params.cpp | 3 ++- src/qe/qe_lite.cpp | 2 +- src/qe/qe_tactic.cpp | 4 ++-- src/sat/tactic/sat_tactic.cpp | 4 ++-- src/smt/smt_solver.cpp | 2 +- src/smt/tactic/smt_tactic_core.cpp | 3 ++- src/smt/tactic/unit_subsumption_tactic.cpp | 2 +- src/solver/solver.cpp | 2 +- src/tactic/arith/add_bounds_tactic.cpp | 4 ++-- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/arith/diff_neq_tactic.cpp | 4 ++-- src/tactic/arith/factor_tactic.cpp | 4 ++-- src/tactic/arith/fix_dl_var_tactic.cpp | 4 ++-- src/tactic/arith/fm_tactic.cpp | 4 ++-- src/tactic/arith/lia2card_tactic.cpp | 4 ++-- src/tactic/arith/lia2pb_tactic.cpp | 4 ++-- src/tactic/arith/pb2bv_tactic.cpp | 4 ++-- src/tactic/arith/propagate_ineqs_tactic.cpp | 4 ++-- src/tactic/arith/purify_arith_tactic.cpp | 2 +- src/tactic/arith/recover_01_tactic.cpp | 4 ++-- src/tactic/bv/bit_blaster_tactic.cpp | 4 ++-- src/tactic/bv/bv1_blaster_tactic.cpp | 4 ++-- src/tactic/bv/bv_bound_chk_tactic.cpp | 4 ++-- src/tactic/bv/bvarray2uf_tactic.cpp | 4 ++-- src/tactic/bv/elim_small_bv_tactic.cpp | 6 +++--- src/tactic/bv/max_bv_sharing_tactic.cpp | 4 ++-- src/tactic/core/blast_term_ite_tactic.cpp | 4 ++-- src/tactic/core/cofactor_term_ite_tactic.cpp | 2 +- src/tactic/core/collect_statistics_tactic.cpp | 2 +- src/tactic/core/ctx_simplify_tactic.cpp | 4 ++-- src/tactic/core/elim_term_ite_tactic.cpp | 4 ++-- src/tactic/core/elim_uncnstr_tactic.cpp | 6 +++--- src/tactic/core/injectivity_tactic.cpp | 4 ++-- src/tactic/core/nnf_tactic.cpp | 2 +- src/tactic/core/propagate_values_tactic.cpp | 4 ++-- src/tactic/core/simplify_tactic.cpp | 4 ++-- src/tactic/core/solve_eqs_tactic.cpp | 4 ++-- src/tactic/core/special_relations_tactic.h | 2 +- src/tactic/core/tseitin_cnf_tactic.cpp | 4 ++-- src/tactic/fpa/fpa2bv_tactic.cpp | 4 ++-- src/tactic/portfolio/solver_subsumption_tactic.cpp | 4 ++-- src/tactic/sls/sls_tactic.cpp | 4 ++-- src/tactic/ufbv/macro_finder_tactic.cpp | 4 ++-- src/tactic/ufbv/quasi_macros_tactic.cpp | 4 ++-- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 2 +- src/util/params.cpp | 10 +++++----- src/util/params.h | 5 +++-- 53 files changed, 101 insertions(+), 98 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 3a6e8e56f..8c6227d7d 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -585,7 +585,7 @@ extern "C" { to_fixedpoint_ref(d)->collect_param_descrs(descrs); to_params(p)->m_params.validate(descrs); to_fixedpoint_ref(d)->updt_params(to_param_ref(p)); - to_fixedpoint(d)->m_params = to_param_ref(p); + to_fixedpoint(d)->m_params.append(to_param_ref(p)); Z3_CATCH; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 0c2461dd6..097dff6db 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -859,8 +859,8 @@ ast_manager & th_rewriter::m() const { } void th_rewriter::updt_params(params_ref const & p) { - m_params = p; - m_imp->cfg().updt_params(p); + m_params.append(p); + m_imp->cfg().updt_params(m_params); } void th_rewriter::get_param_descrs(param_descrs & r) { diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 5b648741c..5a628ce58 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -199,12 +199,12 @@ void tst_params(cmd_context & ctx) { params_ref p1; params_ref p2; p1.set_uint("val", 100); - p2 = p1; + p2.append(p1); SASSERT(p2.get_uint("val", 0) == 100); p2.set_uint("val", 200); SASSERT(p2.get_uint("val", 0) == 200); SASSERT(p1.get_uint("val", 0) == 100); - p2 = p1; + p2.append(p1); SASSERT(p2.get_uint("val", 0) == 100); SASSERT(p1.get_uint("val", 0) == 100); ctx.regular_stream() << "worked" << std::endl; diff --git a/src/math/subpaving/tactic/subpaving_tactic.cpp b/src/math/subpaving/tactic/subpaving_tactic.cpp index 1bc0cb630..6124e726e 100644 --- a/src/math/subpaving/tactic/subpaving_tactic.cpp +++ b/src/math/subpaving/tactic/subpaving_tactic.cpp @@ -227,8 +227,8 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index b66ddf275..6ffd0f745 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -395,8 +395,8 @@ public: char const* name() const override { return "horn"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index ddf85ce19..3baf9da87 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -55,8 +55,8 @@ class nlsat_tactic : public tactic { } void updt_params(params_ref const & p) { - m_params = p; - m_solver.updt_params(p); + m_params.append(p); + m_solver.updt_params(m_params); } bool contains_unsupported(expr_ref_vector & b2a, expr_ref_vector & x2t) { @@ -226,7 +226,7 @@ public: char const* name() const override { return "nlsat"; } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/params/context_params.cpp b/src/params/context_params.cpp index 4bc37b86b..294c5cbbe 100644 --- a/src/params/context_params.cpp +++ b/src/params/context_params.cpp @@ -190,7 +190,8 @@ void context_params::get_solver_params(params_ref & p, bool & proofs_enabled, bo proofs_enabled &= p.get_bool("proof", m_proof); models_enabled &= p.get_bool("model", m_model); unsat_core_enabled = m_unsat_core || p.get_bool("unsat_core", false); - p = merge_default_params(p); + if (!m_auto_config && !p.contains("auto_config")) + p.set_bool("auto_config", false); } diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index f6dd9c712..68ab215a2 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -2466,7 +2466,7 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); // m_imp->updt_params(p); } diff --git a/src/qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp index da1ce5efd..76f4f5715 100644 --- a/src/qe/qe_tactic.cpp +++ b/src/qe/qe_tactic.cpp @@ -103,8 +103,8 @@ public: char const* name() const override { return "qe"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 38c25eae3..892a88f89 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -201,8 +201,8 @@ public: char const* name() const override { return "sat"; } void updt_params(params_ref const & p) override { - m_params = p; - if (m_imp) m_imp->updt_params(p); + m_params.append(p); + if (m_imp) m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index f9ab54327..03f55585a 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -124,7 +124,7 @@ namespace { smt_params m_smt_params_save; void push_params() override { - m_params_save = params_ref(); + m_params_save.reset(); m_params_save.copy(solver::get_params()); m_smt_params_save = m_smt_params; } diff --git a/src/smt/tactic/smt_tactic_core.cpp b/src/smt/tactic/smt_tactic_core.cpp index c99e50393..943facb98 100644 --- a/src/smt/tactic/smt_tactic_core.cpp +++ b/src/smt/tactic/smt_tactic_core.cpp @@ -127,7 +127,8 @@ public: scoped_init_ctx(smt_tactic & o, ast_manager & m):m_owner(o) { m_params = o.fparams(); - m_params_ref = o.params(); + m_params_ref.reset(); + m_params_ref.append(o.params()); smt::kernel * new_ctx = alloc(smt::kernel, m, m_params, m_params_ref); TRACE("smt_tactic", tout << "logic: " << o.m_logic << "\n";); new_ctx->set_logic(o.m_logic); diff --git a/src/smt/tactic/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp index 97ce4a1c1..e0197d15d 100644 --- a/src/smt/tactic/unit_subsumption_tactic.cpp +++ b/src/smt/tactic/unit_subsumption_tactic.cpp @@ -50,7 +50,7 @@ struct unit_subsumption_tactic : public tactic { } void updt_params(params_ref const& p) override { - m_params = p; + m_params.append(p); // m_context.updt_params(p); does not exist. } diff --git a/src/solver/solver.cpp b/src/solver/solver.cpp index b53e3daed..7dcca2ecc 100644 --- a/src/solver/solver.cpp +++ b/src/solver/solver.cpp @@ -226,7 +226,7 @@ void solver::collect_param_descrs(param_descrs & r) { } void solver::reset_params(params_ref const & p) { - m_params = p; + m_params.append(p); solver_params sp(m_params); m_cancel_backup_file = sp.cancel_backup_file(); } diff --git a/src/tactic/arith/add_bounds_tactic.cpp b/src/tactic/arith/add_bounds_tactic.cpp index 4493568bf..33ffbf282 100644 --- a/src/tactic/arith/add_bounds_tactic.cpp +++ b/src/tactic/arith/add_bounds_tactic.cpp @@ -149,8 +149,8 @@ public: char const* name() const override { return "add_bounds"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index fce096f23..3cc7436d1 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -45,7 +45,7 @@ public: char const* name() const override { return "card2bv"; } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/diff_neq_tactic.cpp b/src/tactic/arith/diff_neq_tactic.cpp index 92ce7cd29..4269aff85 100644 --- a/src/tactic/arith/diff_neq_tactic.cpp +++ b/src/tactic/arith/diff_neq_tactic.cpp @@ -360,8 +360,8 @@ public: char const* name() const override { return "diff_neq"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/factor_tactic.cpp b/src/tactic/arith/factor_tactic.cpp index 07b59a3f9..6b9b226b3 100644 --- a/src/tactic/arith/factor_tactic.cpp +++ b/src/tactic/arith/factor_tactic.cpp @@ -297,8 +297,8 @@ public: char const* name() const override { return "factor"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_params.append(p); + m_imp->m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/fix_dl_var_tactic.cpp b/src/tactic/arith/fix_dl_var_tactic.cpp index f2039c378..87061b189 100644 --- a/src/tactic/arith/fix_dl_var_tactic.cpp +++ b/src/tactic/arith/fix_dl_var_tactic.cpp @@ -303,8 +303,8 @@ public: char const* name() const override { return "fix_dl_var"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index ef8109de0..569dbff21 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -1645,8 +1645,8 @@ public: char const* name() const override { return "fm"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index 77786e267..5f6edf6ea 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -135,8 +135,8 @@ public: char const* name() const override { return "lia2card"; } void updt_params(params_ref const & p) override { - m_params = p; - m_compile_equality = p.get_bool("compile_equality", true); + m_params.append(p); + m_compile_equality = m_params.get_bool("compile_equality", true); } expr_ref mk_bounded(expr_ref_vector& axioms, app* x, unsigned lo, unsigned hi) { diff --git a/src/tactic/arith/lia2pb_tactic.cpp b/src/tactic/arith/lia2pb_tactic.cpp index d67f49a37..46404ffb0 100644 --- a/src/tactic/arith/lia2pb_tactic.cpp +++ b/src/tactic/arith/lia2pb_tactic.cpp @@ -308,8 +308,8 @@ public: char const* name() const override { return "lia2pb"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/pb2bv_tactic.cpp b/src/tactic/arith/pb2bv_tactic.cpp index b63c85f1b..2d405895f 100644 --- a/src/tactic/arith/pb2bv_tactic.cpp +++ b/src/tactic/arith/pb2bv_tactic.cpp @@ -1010,8 +1010,8 @@ public: char const* name() const override { return "pb2bv"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/propagate_ineqs_tactic.cpp b/src/tactic/arith/propagate_ineqs_tactic.cpp index d55ea4ecf..0f62b45f4 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.cpp +++ b/src/tactic/arith/propagate_ineqs_tactic.cpp @@ -543,8 +543,8 @@ propagate_ineqs_tactic::~propagate_ineqs_tactic() { } void propagate_ineqs_tactic::updt_params(params_ref const & p) { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void propagate_ineqs_tactic::operator()(goal_ref const & g, diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index db43a3ee6..9c07bcadc 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -906,7 +906,7 @@ public: char const* name() const override { return "purify_arith"; } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/arith/recover_01_tactic.cpp b/src/tactic/arith/recover_01_tactic.cpp index a7cef82e3..251d78e72 100644 --- a/src/tactic/arith/recover_01_tactic.cpp +++ b/src/tactic/arith/recover_01_tactic.cpp @@ -401,8 +401,8 @@ public: char const* name() const override { return "recover_01"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/bv/bit_blaster_tactic.cpp b/src/tactic/bv/bit_blaster_tactic.cpp index 744f207f3..978a0a9a6 100644 --- a/src/tactic/bv/bit_blaster_tactic.cpp +++ b/src/tactic/bv/bit_blaster_tactic.cpp @@ -122,8 +122,8 @@ public: char const* name() const override { return "bit_blaster"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/bv/bv1_blaster_tactic.cpp b/src/tactic/bv/bv1_blaster_tactic.cpp index 3af58bf66..0fc38f2db 100644 --- a/src/tactic/bv/bv1_blaster_tactic.cpp +++ b/src/tactic/bv/bv1_blaster_tactic.cpp @@ -434,8 +434,8 @@ public: char const* name() const override { return "bv1_blaster"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_params.append(p); + m_imp->m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/bv/bv_bound_chk_tactic.cpp b/src/tactic/bv/bv_bound_chk_tactic.cpp index e0b6e4d81..7ea7c0a69 100644 --- a/src/tactic/bv/bv_bound_chk_tactic.cpp +++ b/src/tactic/bv/bv_bound_chk_tactic.cpp @@ -206,8 +206,8 @@ tactic * bv_bound_chk_tactic::translate(ast_manager & m) { void bv_bound_chk_tactic::updt_params(params_ref const & p) { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void bv_bound_chk_tactic::cleanup() { diff --git a/src/tactic/bv/bvarray2uf_tactic.cpp b/src/tactic/bv/bvarray2uf_tactic.cpp index d0bd6538b..da86ed663 100644 --- a/src/tactic/bv/bvarray2uf_tactic.cpp +++ b/src/tactic/bv/bvarray2uf_tactic.cpp @@ -116,8 +116,8 @@ public: char const* name() const override { return "bvarray2uf"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 7c72abde9..eef85ebba 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -207,7 +207,7 @@ class elim_small_bv_tactic : public tactic { } void updt_params(params_ref const & p) { - m_params = p; + m_params.append(p); m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_max_steps = p.get_uint("max_steps", UINT_MAX); m_max_bits = p.get_uint("max_bits", 4); @@ -241,8 +241,8 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; - m_rw.cfg().updt_params(p); + m_params.append(p); + m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 0efe4f58c..2bc99806e 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -280,8 +280,8 @@ public: char const* name() const override { return "max_bv_sharing"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_params.append(p); + m_imp->m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/blast_term_ite_tactic.cpp b/src/tactic/core/blast_term_ite_tactic.cpp index fe1269732..38b4e172e 100644 --- a/src/tactic/core/blast_term_ite_tactic.cpp +++ b/src/tactic/core/blast_term_ite_tactic.cpp @@ -174,8 +174,8 @@ public: char const* name() const override { return "blast_term_ite"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->m_rw.m_cfg.updt_params(p); + m_params.append(p); + m_imp->m_rw.m_cfg.updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/cofactor_term_ite_tactic.cpp b/src/tactic/core/cofactor_term_ite_tactic.cpp index d1b8f5b1b..234b7262c 100644 --- a/src/tactic/core/cofactor_term_ite_tactic.cpp +++ b/src/tactic/core/cofactor_term_ite_tactic.cpp @@ -52,7 +52,7 @@ public: ~cofactor_term_ite_tactic() override {} char const* name() const override { return "cofactor"; } - void updt_params(params_ref const & p) override { m_params = p; m_elim_ite.updt_params(p); } + void updt_params(params_ref const & p) override { m_params.append(p); m_elim_ite.updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { m_elim_ite.collect_param_descrs(r); } void operator()(goal_ref const & g, goal_ref_buffer& result) override { diff --git a/src/tactic/core/collect_statistics_tactic.cpp b/src/tactic/core/collect_statistics_tactic.cpp index 3d8ebfb12..e507f49dd 100644 --- a/src/tactic/core/collect_statistics_tactic.cpp +++ b/src/tactic/core/collect_statistics_tactic.cpp @@ -60,7 +60,7 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); } void collect_param_descrs(param_descrs & r) override {} diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index c8aa1a4c4..47b2fa389 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -605,8 +605,8 @@ ctx_simplify_tactic::~ctx_simplify_tactic() { } void ctx_simplify_tactic::updt_params(params_ref const & p) { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void ctx_simplify_tactic::get_param_descrs(param_descrs & r) { diff --git a/src/tactic/core/elim_term_ite_tactic.cpp b/src/tactic/core/elim_term_ite_tactic.cpp index 42adf04a9..2a0593ade 100644 --- a/src/tactic/core/elim_term_ite_tactic.cpp +++ b/src/tactic/core/elim_term_ite_tactic.cpp @@ -143,8 +143,8 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->m_rw.cfg().updt_params(p); + m_params.append(p); + m_imp->m_rw.cfg().updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index a9f5ffcf8..26a69fd4a 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -862,9 +862,9 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_max_steps = p.get_uint("max_steps", UINT_MAX); + m_params.append(p); + m_max_memory = megabytes_to_bytes(m_params.get_uint("max_memory", UINT_MAX)); + m_max_steps = m_params.get_uint("max_steps", UINT_MAX); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/injectivity_tactic.cpp b/src/tactic/core/injectivity_tactic.cpp index 485eda4dd..dfcb152a2 100644 --- a/src/tactic/core/injectivity_tactic.cpp +++ b/src/tactic/core/injectivity_tactic.cpp @@ -258,8 +258,8 @@ public: char const* name() const override { return "injectivity"; } void updt_params(params_ref const & p) override { - m_params = p; - m_finder->updt_params(p); + m_params.append(p); + m_finder->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/nnf_tactic.cpp b/src/tactic/core/nnf_tactic.cpp index 164cf9311..fccfdf53e 100644 --- a/src/tactic/core/nnf_tactic.cpp +++ b/src/tactic/core/nnf_tactic.cpp @@ -51,7 +51,7 @@ public: char const* name() const override { return "nnf"; } - void updt_params(params_ref const & p) override { m_params = p; } + void updt_params(params_ref const & p) override { m_params.append(p); } void collect_param_descrs(param_descrs & r) override { nnf::get_param_descrs(r); } diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index b735de4b7..b2ed7cab9 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -219,9 +219,9 @@ public: char const* name() const override { return "propagate_values"; } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); m_r.updt_params(p); - updt_params_core(p); + updt_params_core(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/simplify_tactic.cpp b/src/tactic/core/simplify_tactic.cpp index ca76cafc7..8d9ff759f 100644 --- a/src/tactic/core/simplify_tactic.cpp +++ b/src/tactic/core/simplify_tactic.cpp @@ -80,8 +80,8 @@ simplify_tactic::~simplify_tactic() { } void simplify_tactic::updt_params(params_ref const & p) { - m_params = p; - m_imp->m_r.updt_params(p); + m_params.append(p); + m_imp->m_r.updt_params(m_params); } void simplify_tactic::get_param_descrs(param_descrs & r) { diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 9d844b7ed..a73fe88b6 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -1092,8 +1092,8 @@ public: char const* name() const override { return "solve_eqs"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/core/special_relations_tactic.h b/src/tactic/core/special_relations_tactic.h index a1cafb7c0..dae38304a 100644 --- a/src/tactic/core/special_relations_tactic.h +++ b/src/tactic/core/special_relations_tactic.h @@ -49,7 +49,7 @@ public: ~special_relations_tactic() override {} - void updt_params(params_ref const & p) override { m_params = p; } + void updt_params(params_ref const & p) override { m_params.append(p); } void collect_param_descrs(param_descrs & r) override { } diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index e26fded8f..c141aaa3b 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -894,8 +894,8 @@ public: char const* name() const override { return "tseitin_cnf"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index be98dea00..282439228 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -123,8 +123,8 @@ public: char const* name() const override { return "fp2bv"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/portfolio/solver_subsumption_tactic.cpp b/src/tactic/portfolio/solver_subsumption_tactic.cpp index 6b275508b..c92968c8c 100644 --- a/src/tactic/portfolio/solver_subsumption_tactic.cpp +++ b/src/tactic/portfolio/solver_subsumption_tactic.cpp @@ -136,8 +136,8 @@ public: char const* name() const override { return "solver_subsumption"; } void updt_params(params_ref const& p) override { - m_params = p; - unsigned max_conflicts = p.get_uint("max_conflicts", 2); + m_params.append(p); + unsigned max_conflicts = m_params.get_uint("max_conflicts", 2); m_params.set_uint("sat.max_conflicts", max_conflicts); m_params.set_uint("smt.max_conflicts", max_conflicts); } diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index ece6940f3..e631c23e9 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -53,8 +53,8 @@ public: char const* name() const override { return "sls"; } void updt_params(params_ref const & p) override { - m_params = p; - m_engine->updt_params(p); + m_params.append(p); + m_engine->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index c5745d85c..2358abcd1 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -108,8 +108,8 @@ public: char const* name() const override { return "macro_finder"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 0e0cb7cb2..b0eb113b8 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -103,8 +103,8 @@ public: char const* name() const override { return "quasi_macros"; } void updt_params(params_ref const & p) override { - m_params = p; - m_imp->updt_params(p); + m_params.append(p); + m_imp->updt_params(m_params); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index d5bfec8fe..e254523c0 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -35,7 +35,7 @@ public: } void updt_params(params_ref const & p) override { - m_params = p; + m_params.append(p); } void collect_param_descrs(param_descrs & r) override { diff --git a/src/util/params.cpp b/src/util/params.cpp index 1819684e0..4911664f1 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -520,7 +520,7 @@ params_ref::~params_ref() { params_ref::params_ref(params_ref const & p): m_params(nullptr) { - operator=(p); + set(p); } void params_ref::display(std::ostream & out) const { @@ -553,18 +553,18 @@ void params_ref::validate(param_descrs const & p) { m_params->validate(p); } -params_ref & params_ref::operator=(params_ref const & p) { + +void params_ref::set(params_ref const & p) { if (p.m_params) p.m_params->inc_ref(); if (m_params) m_params->dec_ref(); m_params = p.m_params; - return *this; } void params_ref::copy(params_ref const & src) { - if (m_params == nullptr) - operator=(src); + if (m_params == nullptr || m_params->empty()) + set(src); else { init(); copy_core(src.m_params); diff --git a/src/util/params.h b/src/util/params.h index 989d112bd..da05dff90 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -35,6 +35,8 @@ class params_ref { params * m_params; void init(); void copy_core(params const * p); + params_ref& operator=(params_ref const& p) = delete; + void set(params_ref const& p); public: params_ref():m_params(nullptr) {} params_ref(params_ref const & p); @@ -42,8 +44,7 @@ public: static params_ref const & get_empty() { return g_empty_params_ref; } - params_ref & operator=(params_ref const & p); - + // copy params from src void copy(params_ref const & src); void append(params_ref const & src) { copy(src); } From 79f0ceac4ca103ab4eff77f4e991327a4b143c74 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 30 Dec 2021 19:13:23 -0800 Subject: [PATCH 42/88] na Signed-off-by: Nikolaj Bjorner --- src/tactic/bv/elim_small_bv_tactic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index eef85ebba..12c756c6e 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -208,9 +208,9 @@ class elim_small_bv_tactic : public tactic { void updt_params(params_ref const & p) { m_params.append(p); - m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); - m_max_steps = p.get_uint("max_steps", UINT_MAX); - m_max_bits = p.get_uint("max_bits", 4); + m_max_memory = megabytes_to_bytes(m_params.get_uint("max_memory", UINT_MAX)); + m_max_steps = m_params.get_uint("max_steps", UINT_MAX); + m_max_bits = m_params.get_uint("max_bits", 4); } }; From aa901c4e88438559186e408ab87854173670878d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Dec 2021 11:53:40 -0800 Subject: [PATCH 43/88] axiom solver improvements --- src/ast/rewriter/th_rewriter.cpp | 4 +- src/sat/smt/array_axioms.cpp | 7 +- src/sat/smt/array_internalize.cpp | 109 ++++++++++++++----------- src/sat/smt/array_solver.cpp | 12 +-- src/sat/smt/array_solver.h | 12 ++- src/sat/smt/euf_ackerman.cpp | 10 +-- src/sat/smt/euf_solver.cpp | 11 ++- src/tactic/bv/elim_small_bv_tactic.cpp | 8 +- 8 files changed, 98 insertions(+), 75 deletions(-) diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 097dff6db..2aaf4626c 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -627,7 +627,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { count_down_subterm_references(result, reference_map); // Any term that was newly introduced by the rewrite step is only referenced within / reachable from the result term. - for (auto kv : reference_map) { + for (auto const& kv : reference_map) { if (kv.m_value == 0) { m().trace_stream() << "[attach-enode] #" << kv.m_key->get_id() << " 0\n"; } @@ -691,7 +691,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg { return; if (m_new_subst) { m_rep.reset(); - for (auto kv : m_subst->sub()) + for (auto const& kv : m_subst->sub()) m_rep.insert(kv.m_key, kv.m_value); m_new_subst = false; } diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 62f111ea6..6f823aee7 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -537,8 +537,8 @@ namespace array { m_delay_qhead = 0; for (; m_delay_qhead < sz; ++m_delay_qhead) - if (m_axiom_trail[m_delay_qhead].is_delayed() && assert_axiom(m_delay_qhead)) - change = true; + if (m_axiom_trail[m_delay_qhead].is_delayed() && assert_axiom(m_delay_qhead)) + change = true; flet _enable_delay(m_enable_delay, false); if (unit_propagate()) change = true; @@ -561,7 +561,8 @@ namespace array { expr_ref _e(a.mk_select(select.size(), select.data()), m); euf::enode* e = e_internalize(_e); if (e->get_root() != p->get_root()) { - add_unit(eq_internalize(_e, p->get_expr())); + sat::literal eq = eq_internalize(_e, p->get_expr()); + add_unit(eq); change = true; } } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index b74d46fe6..da129f30f 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -49,7 +49,7 @@ namespace array { if (v == euf::null_theory_var) { mk_var(n); if (is_lambda(n->get_expr())) - internalize_lambda(n); + internalize_eh_lambda(n); } } @@ -57,46 +57,6 @@ namespace array { ensure_var(n); } - void solver::internalize_store(euf::enode* n) { - //std::cout << "store th-var " << n->get_th_var(get_id()) << "\n"; - add_parent_lambda(n->get_arg(0)->get_th_var(get_id()), n); - push_axiom(store_axiom(n)); - add_lambda(n->get_th_var(get_id()), n); - SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); - } - - void solver::internalize_map(euf::enode* n) { - for (auto* arg : euf::enode_args(n)) { - add_parent_lambda(arg->get_th_var(get_id()), n); - set_prop_upward(arg); - } - push_axiom(default_axiom(n)); - add_lambda(n->get_th_var(get_id()), n); - //SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); - } - - void solver::internalize_lambda(euf::enode* n) { - SASSERT(is_lambda(n->get_expr()) || a.is_const(n->get_expr()) || a.is_as_array(n->get_expr())); - theory_var v = n->get_th_var(get_id()); - push_axiom(default_axiom(n)); - add_lambda(v, n); - set_prop_upward(v); - } - - void solver::internalize_select(euf::enode* n) { - add_parent_select(n->get_arg(0)->get_th_var(get_id()), n); - } - - void solver::internalize_ext(euf::enode* n) { - SASSERT(is_array(n->get_arg(0))); - push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1))); - } - - void solver::internalize_default(euf::enode* n) { - add_parent_default(n->get_arg(0)->get_th_var(get_id()), n); - set_prop_upward(n); - } - bool solver::visited(expr* e) { euf::enode* n = expr2enode(e); return n && n->is_attached_to(get_id()); @@ -125,35 +85,90 @@ namespace array { mk_var(n); for (auto* arg : euf::enode_args(n)) ensure_var(arg); + internalize_eh(n); if (ctx.is_relevant(n) || !ctx.relevancy().enabled()) relevant_eh(n); return true; } + void solver::internalize_eh_lambda(euf::enode* n) { + SASSERT(is_lambda(n->get_expr()) || a.is_const(n->get_expr()) || a.is_map(n->get_expr()) || a.is_as_array(n->get_expr())); + theory_var v = n->get_th_var(get_id()); + push_axiom(default_axiom(n)); + add_lambda(v, n); + } + + void solver::internalize_eh(euf::enode* n) { + if (is_lambda(n->get_expr())) { + internalize_eh_lambda(n); + return; + } + switch (n->get_decl()->get_decl_kind()) { + case OP_STORE: + push_axiom(store_axiom(n)); + break; + case OP_SELECT: + break; + case OP_AS_ARRAY: + case OP_CONST_ARRAY: + internalize_eh_lambda(n); + // SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); + break; + case OP_ARRAY_EXT: + SASSERT(is_array(n->get_arg(0))); + push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1))); + break; + case OP_ARRAY_DEFAULT: + add_parent_default(n->get_arg(0)->get_th_var(get_id()), n); + break; + case OP_ARRAY_MAP: + for (auto* arg : euf::enode_args(n)) + add_parent_lambda(arg->get_th_var(get_id()), n); + internalize_eh_lambda(n); + break; + case OP_SET_UNION: + case OP_SET_INTERSECT: + case OP_SET_DIFFERENCE: + case OP_SET_COMPLEMENT: + case OP_SET_SUBSET: + case OP_SET_HAS_SIZE: + case OP_SET_CARD: + ctx.unhandled_function(n->get_decl()); + break; + default: + UNREACHABLE(); + break; + } + } + void solver::relevant_eh(euf::enode* n) { + if (is_lambda(n->get_expr())) { + set_prop_upward(n->get_th_var(get_id())); + return; + } if (!is_app(n->get_expr())) return; if (n->get_decl()->get_family_id() != a.get_family_id()) return; switch (n->get_decl()->get_decl_kind()) { case OP_STORE: - internalize_store(n); + add_parent_lambda(n->get_arg(0)->get_th_var(get_id()), n); break; case OP_SELECT: - internalize_select(n); + add_parent_select(n->get_arg(0)->get_th_var(get_id()), n); break; case OP_AS_ARRAY: case OP_CONST_ARRAY: - internalize_lambda(n); + set_prop_upward(n->get_th_var(get_id())); break; case OP_ARRAY_EXT: - internalize_ext(n); break; case OP_ARRAY_DEFAULT: - internalize_default(n); + set_prop_upward(n->get_arg(0)->get_th_var(get_id())); break; case OP_ARRAY_MAP: - internalize_map(n); + for (auto* arg : euf::enode_args(n)) + set_prop_upward_store(arg); break; case OP_SET_UNION: case OP_SET_INTERSECT: diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 15978747c..83fa15f41 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -187,7 +187,7 @@ namespace array { set_prop_upward(d); ctx.push_vec(d.m_lambdas, lambda); if (should_set_prop_upward(d)) { - set_prop_upward(lambda); + set_prop_upward_store(lambda); propagate_select_axioms(d, lambda); } } @@ -196,8 +196,8 @@ namespace array { SASSERT(can_beta_reduce(lambda)); auto& d = get_var_data(find(v_child)); ctx.push_vec(d.m_parent_lambdas, lambda); - if (should_set_prop_upward(d)) - propagate_select_axioms(d, lambda); +// if (should_set_prop_upward(d)) +// propagate_select_axioms(d, lambda); } void solver::add_parent_default(theory_var v, euf::enode* def) { @@ -227,6 +227,8 @@ namespace array { return; auto& d = get_var_data(v); + if (!d.m_prop_upward) + return; for (euf::enode* lambda : d.m_lambdas) propagate_select_axioms(d, lambda); @@ -246,14 +248,14 @@ namespace array { set_prop_upward(d); } - void solver::set_prop_upward(euf::enode* n) { + void solver::set_prop_upward_store(euf::enode* n) { if (a.is_store(n->get_expr())) set_prop_upward(n->get_arg(0)->get_th_var(get_id())); } void solver::set_prop_upward(var_data& d) { for (auto* p : d.m_lambdas) - set_prop_upward(p); + set_prop_upward_store(p); } /** diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 74788254b..b4fd0d95e 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -73,12 +73,8 @@ namespace array { bool visited(expr* e) override; bool post_visit(expr* e, bool sign, bool root) override; void ensure_var(euf::enode* n); - void internalize_store(euf::enode* n); - void internalize_select(euf::enode* n); - void internalize_lambda(euf::enode* n); - void internalize_ext(euf::enode* n); - void internalize_default(euf::enode* n); - void internalize_map(euf::enode* n); + void internalize_eh_lambda(euf::enode* n); + void internalize_eh(euf::enode* n); // axioms struct axiom_record { @@ -205,7 +201,7 @@ namespace array { void set_prop_upward(theory_var v); void set_prop_upward(var_data& d); - void set_prop_upward(euf::enode* n); + void set_prop_upward_store(euf::enode* n); unsigned get_lambda_equiv_size(var_data const& d) const; bool should_set_prop_upward(var_data const& d) const; bool should_prop_upward(var_data const& d) const; @@ -231,6 +227,8 @@ namespace array { void set_else(theory_var v, expr* e); expr* get_else(theory_var v); + void internalized(euf::enode* n); + // diagnostics std::ostream& display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const; std::ostream& display(std::ostream& out, axiom_record const& r) const; diff --git a/src/sat/smt/euf_ackerman.cpp b/src/sat/smt/euf_ackerman.cpp index 941b1e0ac..c26835f99 100644 --- a/src/sat/smt/euf_ackerman.cpp +++ b/src/sat/smt/euf_ackerman.cpp @@ -176,10 +176,10 @@ namespace euf { unsigned sz = a->get_num_args(); for (unsigned i = 0; i < sz; ++i) { - expr_ref eq(m.mk_eq(a->get_arg(i), b->get_arg(i)), m); + expr_ref eq = s.mk_eq(a->get_arg(i), b->get_arg(i)); lits.push_back(~s.mk_literal(eq)); } - expr_ref eq(m.mk_eq(a, b), m); + expr_ref eq = s.mk_eq(a, b); lits.push_back(s.mk_literal(eq)); s.s().mk_clause(lits, sat::status::th(true, m.get_basic_family_id())); } @@ -187,9 +187,9 @@ namespace euf { void ackerman::add_eq(expr* a, expr* b, expr* c) { flet _is_redundant(s.m_is_redundant, true); sat::literal lits[3]; - expr_ref eq1(m.mk_eq(a, c), m); - expr_ref eq2(m.mk_eq(b, c), m); - expr_ref eq3(m.mk_eq(a, b), m); + expr_ref eq1(s.mk_eq(a, c), m); + expr_ref eq2(s.mk_eq(b, c), m); + expr_ref eq3(s.mk_eq(a, b), m); TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << "\n";); lits[0] = ~s.mk_literal(eq1); lits[1] = ~s.mk_literal(eq2); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index b8bd601e3..8f7c34719 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -296,9 +296,14 @@ namespace euf { } void solver::asserted(literal l) { + if (m_relevancy.enabled() && !m_relevancy.is_relevant(l)) { - m_relevancy.asserted(l); - return; + if (s().lvl(l) <= s().search_lvl()) + mark_relevant(l); + else { + m_relevancy.asserted(l); + return; + } } expr* e = m_bool_var2expr.get(l.var(), nullptr); @@ -742,7 +747,7 @@ namespace euf { void solver::relevant_eh(euf::enode* n) { if (m_qsolver) m_qsolver->relevant_eh(n); - for (auto thv : enode_th_vars(n)) { + for (auto const& thv : enode_th_vars(n)) { auto* th = m_id2solver.get(thv.get_id(), nullptr); if (th && th != m_qsolver) th->relevant_eh(n); diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index 12c756c6e..02ec522c6 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -145,11 +145,13 @@ class elim_small_bv_tactic : public tactic { "; sort = " << mk_ismt2_pp(s, m) << "; body = " << mk_ismt2_pp(body, m) << std::endl;); - if (bv_sz >= 31ul || ((unsigned)(1ul << bv_sz)) + num_steps > m_max_steps) { + if (bv_sz >= 31) + return false; + unsigned max_num = 1u << bv_sz; + if (max_num > m_max_steps || max_num + num_steps > m_max_steps) return false; - } - for (unsigned j = 0; j < (1ul << bv_sz) && !max_steps_exceeded(num_steps); j++) { + for (unsigned j = 0; j < max_num && !max_steps_exceeded(num_steps); j++) { expr_ref n(m_util.mk_numeral(j, bv_sz), m); new_bodies.push_back(replace_var(uv, num_decls, max_var_idx_p1, i, s, body, n)); num_steps++; From 0ef0ed3b9461ac43683b9c6233d58da29f8be902 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Dec 2021 15:51:52 -0800 Subject: [PATCH 44/88] redoing arrays --- src/sat/smt/array_axioms.cpp | 3 ++- src/sat/smt/array_internalize.cpp | 36 ++++++++++++-------------- src/sat/smt/array_solver.cpp | 16 ++++++------ src/sat/smt/array_solver.h | 7 +++--- src/sat/smt/euf_solver.cpp | 7 ++---- src/sat/smt/smt_relevant.cpp | 42 +++++++++++++++++++++---------- src/sat/smt/smt_relevant.h | 2 +- 7 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 6f823aee7..6e0310bdd 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -517,13 +517,14 @@ namespace array { unsigned num_vars = get_num_vars(); bool change = false; for (unsigned v = 0; v < num_vars; v++) { - propagate_parent_select_axioms(v); auto& d = get_var_data(v); if (!d.m_prop_upward) continue; euf::enode* n = var2enode(v); if (!ctx.is_relevant(n)) continue; + for (euf::enode* lambda : d.m_parent_lambdas) + propagate_select_axioms(d, lambda); if (add_as_array_eqs(n)) change = true; bool has_default = false; diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index da129f30f..e45d59bd9 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -49,7 +49,7 @@ namespace array { if (v == euf::null_theory_var) { mk_var(n); if (is_lambda(n->get_expr())) - internalize_eh_lambda(n); + internalize_lambda_eh(n); } } @@ -91,18 +91,13 @@ namespace array { return true; } - void solver::internalize_eh_lambda(euf::enode* n) { - SASSERT(is_lambda(n->get_expr()) || a.is_const(n->get_expr()) || a.is_map(n->get_expr()) || a.is_as_array(n->get_expr())); - theory_var v = n->get_th_var(get_id()); + void solver::internalize_lambda_eh(euf::enode* n) { push_axiom(default_axiom(n)); - add_lambda(v, n); + auto& d = get_var_data(find(n)); + ctx.push_vec(d.m_lambdas, n); } void solver::internalize_eh(euf::enode* n) { - if (is_lambda(n->get_expr())) { - internalize_eh_lambda(n); - return; - } switch (n->get_decl()->get_decl_kind()) { case OP_STORE: push_axiom(store_axiom(n)); @@ -111,20 +106,19 @@ namespace array { break; case OP_AS_ARRAY: case OP_CONST_ARRAY: - internalize_eh_lambda(n); - // SASSERT(!get_var_data(n->get_th_var(get_id())).m_prop_upward); + internalize_lambda_eh(n); break; case OP_ARRAY_EXT: SASSERT(is_array(n->get_arg(0))); push_axiom(extensionality_axiom(n->get_arg(0), n->get_arg(1))); break; case OP_ARRAY_DEFAULT: - add_parent_default(n->get_arg(0)->get_th_var(get_id()), n); + add_parent_default(find(n->get_arg(0)), n); break; case OP_ARRAY_MAP: for (auto* arg : euf::enode_args(n)) - add_parent_lambda(arg->get_th_var(get_id()), n); - internalize_eh_lambda(n); + add_parent_lambda(find(arg), n); + internalize_lambda_eh(n); break; case OP_SET_UNION: case OP_SET_INTERSECT: @@ -143,7 +137,7 @@ namespace array { void solver::relevant_eh(euf::enode* n) { if (is_lambda(n->get_expr())) { - set_prop_upward(n->get_th_var(get_id())); + set_prop_upward(find(n)); return; } if (!is_app(n->get_expr())) @@ -152,23 +146,25 @@ namespace array { return; switch (n->get_decl()->get_decl_kind()) { case OP_STORE: - add_parent_lambda(n->get_arg(0)->get_th_var(get_id()), n); + add_parent_lambda(find(n->get_arg(0)), n); break; case OP_SELECT: - add_parent_select(n->get_arg(0)->get_th_var(get_id()), n); + add_parent_select(find(n->get_arg(0)), n); break; - case OP_AS_ARRAY: case OP_CONST_ARRAY: - set_prop_upward(n->get_th_var(get_id())); + case OP_AS_ARRAY: + set_prop_upward(find(n)); + add_parent_default(find(n), n); break; case OP_ARRAY_EXT: break; case OP_ARRAY_DEFAULT: - set_prop_upward(n->get_arg(0)->get_th_var(get_id())); + set_prop_upward(find(n->get_arg(0))); break; case OP_ARRAY_MAP: for (auto* arg : euf::enode_args(n)) set_prop_upward_store(arg); + set_prop_upward(find(n)); break; case OP_SET_UNION: case OP_SET_INTERSECT: diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index 83fa15f41..f3414a4c6 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -186,18 +186,17 @@ namespace array { if (should_set_prop_upward(d)) set_prop_upward(d); ctx.push_vec(d.m_lambdas, lambda); - if (should_set_prop_upward(d)) { - set_prop_upward_store(lambda); - propagate_select_axioms(d, lambda); - } + propagate_select_axioms(d, lambda); + if (should_set_prop_upward(d)) + set_prop_upward_store(lambda); } void solver::add_parent_lambda(theory_var v_child, euf::enode* lambda) { SASSERT(can_beta_reduce(lambda)); auto& d = get_var_data(find(v_child)); ctx.push_vec(d.m_parent_lambdas, lambda); -// if (should_set_prop_upward(d)) -// propagate_select_axioms(d, lambda); + if (should_prop_upward(d)) + propagate_select_axioms(d, lambda); } void solver::add_parent_default(theory_var v, euf::enode* def) { @@ -227,12 +226,13 @@ namespace array { return; auto& d = get_var_data(v); - if (!d.m_prop_upward) - return; for (euf::enode* lambda : d.m_lambdas) propagate_select_axioms(d, lambda); + if (!should_prop_upward(d)) + return; + for (euf::enode* lambda : d.m_parent_lambdas) propagate_select_axioms(d, lambda); } diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index b4fd0d95e..1e596bec1 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -66,6 +66,7 @@ namespace array { array_union_find m_find; theory_var find(theory_var v) { return m_find.find(v); } + theory_var find(euf::enode* n) { return find(n->get_th_var(get_id())); } func_decl_ref_vector const& sort2diff(sort* s); // internalize @@ -73,8 +74,8 @@ namespace array { bool visited(expr* e) override; bool post_visit(expr* e, bool sign, bool root) override; void ensure_var(euf::enode* n); - void internalize_eh_lambda(euf::enode* n); void internalize_eh(euf::enode* n); + void internalize_lambda_eh(euf::enode* n); // axioms struct axiom_record { @@ -192,7 +193,7 @@ namespace array { // solving void add_parent_select(theory_var v_child, euf::enode* select); void add_parent_default(theory_var v_child, euf::enode* def); - void add_lambda(theory_var v, euf::enode* lambda); + void add_lambda(theory_var v, euf::enode* lambda); void add_parent_lambda(theory_var v_child, euf::enode* lambda); void propagate_select_axioms(var_data const& d, euf::enode* a); @@ -227,8 +228,6 @@ namespace array { void set_else(theory_var v, expr* e); expr* get_else(theory_var v); - void internalized(euf::enode* n); - // diagnostics std::ostream& display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const; std::ostream& display(std::ostream& out, axiom_record const& r) const; diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 8f7c34719..eeb195429 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -298,12 +298,9 @@ namespace euf { void solver::asserted(literal l) { if (m_relevancy.enabled() && !m_relevancy.is_relevant(l)) { - if (s().lvl(l) <= s().search_lvl()) - mark_relevant(l); - else { - m_relevancy.asserted(l); + m_relevancy.asserted(l); + if (!m_relevancy.is_relevant(l)) return; - } } expr* e = m_bool_var2expr.get(l.var(), nullptr); diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index 1f57dc20a..a037090a2 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -241,19 +241,35 @@ namespace smt { } void relevancy::propagate_relevant(euf::enode* n) { - m_stack.push_back(n); - while (!m_stack.empty()) { - n = m_stack.back(); - unsigned sz = m_stack.size(); - for (euf::enode* arg : euf::enode_args(n)) - if (!arg->is_relevant()) - m_stack.push_back(arg); - if (sz == m_stack.size()) { - ctx.get_egraph().set_relevant(n); - relevant_eh(n); - for (euf::enode* sib : euf::enode_class(n)) - if (!sib->is_relevant()) - mark_relevant(sib); + m_todo.push_back(n); + while (!m_todo.empty()) { + n = m_todo.back(); + m_todo.pop_back(); + if (n->is_relevant()) + continue; + if (ctx.get_si().is_bool_op(n->get_expr())) + continue; + m_stack.push_back(n); + while (!m_stack.empty()) { + n = m_stack.back(); + unsigned sz = m_stack.size(); + for (euf::enode* arg : euf::enode_args(n)) + if (!arg->is_relevant()) + m_stack.push_back(arg); + if (sz != m_stack.size()) + continue; + if (!n->is_relevant()) { + ctx.get_egraph().set_relevant(n); + relevant_eh(n); + for (euf::enode* sib : euf::enode_class(n)) + if (!sib->is_relevant()) + m_todo.push_back(sib); + } + if (!ctx.get_manager().inc()) { + m_todo.reset(); + m_stack.reset(); + return; + } m_stack.pop_back(); } } diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index fbef05b78..723cf613a 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -119,7 +119,7 @@ namespace smt { vector m_occurs; // where do literals occur unsigned m_qhead = 0; // queue head for relevancy svector> m_queue; // propagation queue for relevancy - euf::enode_vector m_stack; + euf::enode_vector m_stack, m_todo; // callbacks during propagation void relevant_eh(euf::enode* n); From 955032106467acd2863572f0e2cdf7cd0e9c4f08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Dec 2021 16:33:06 -0800 Subject: [PATCH 45/88] missed push lambdas --- src/sat/smt/array_internalize.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index e45d59bd9..5e285112d 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -99,7 +99,8 @@ namespace array { void solver::internalize_eh(euf::enode* n) { switch (n->get_decl()->get_decl_kind()) { - case OP_STORE: + case OP_STORE: + ctx.push_vec(get_var_data(find(n)).m_lambdas, n); push_axiom(store_axiom(n)); break; case OP_SELECT: From a44a46a514f3c755a958f19e06a97e5933647131 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Dec 2021 16:41:51 -0800 Subject: [PATCH 46/88] fix #5745 --- src/cmd_context/basic_cmds.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 23915f7fe..823f48e01 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -301,10 +301,23 @@ UNARY_CMD(pp_cmd, "display", "", "display the given term.", CPK_EXPR, expr ctx.regular_stream() << std::endl; }); -UNARY_CMD(echo_cmd, "echo", "", "display the given string", CPK_STRING, char const *, - bool smt2c = ctx.params().m_smtlib2_compliant; - ctx.regular_stream() << (smt2c ? "\"" : "") << arg << (smt2c ? "\"" : "") << std::endl;); +static std::string escape_string(char const* arg) { + std::string result; + while (*arg) { + auto ch = *arg++; + if (ch == '"') + result.push_back(ch); + result.push_back(ch); + } + return result; +} +UNARY_CMD(echo_cmd, "echo", "", "display the given string", CPK_STRING, char const *, + bool smt2c = ctx.params().m_smtlib2_compliant; + if (smt2c) + ctx.regular_stream() << "\"" << escape_string(arg) << "\"" << std::endl; + else + ctx.regular_stream() << arg << std::endl;); class set_get_option_cmd : public cmd { protected: From ca18150c234327da63fc006aeb97e49140fec19a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 Dec 2021 16:43:07 -0800 Subject: [PATCH 47/88] bypass append when src is empty Signed-off-by: Nikolaj Bjorner --- src/util/params.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/params.cpp b/src/util/params.cpp index 4911664f1..aefe4e074 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -565,6 +565,8 @@ void params_ref::set(params_ref const & p) { void params_ref::copy(params_ref const & src) { if (m_params == nullptr || m_params->empty()) set(src); + else if (src.empty()) + return; else { init(); copy_core(src.m_params); From a20b577b2fd6a0c956e62f2cd69327ce1848dcb3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 11:26:38 -0800 Subject: [PATCH 48/88] na --- src/sat/smt/array_axioms.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index 6e0310bdd..b4ab89d1f 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -236,8 +236,7 @@ namespace array { * Assert * select(const(v), i) = v */ - bool solver::assert_select_const_axiom(app* select, app* cnst) { - + bool solver::assert_select_const_axiom(app* select, app* cnst) { ++m_stats.m_num_select_const_axiom; expr* val = nullptr; VERIFY(a.is_const(cnst, val)); From 84f514a4f4f5835b86f57c78dd3ab3eedf6aad0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 15:33:33 -0800 Subject: [PATCH 49/88] throttle ackerman on arrays --- src/ast/euf/euf_egraph.cpp | 8 ++++---- src/sat/smt/arith_solver.h | 1 + src/sat/smt/array_solver.h | 3 ++- src/sat/smt/euf_ackerman.cpp | 30 +++++++++++++++++++++++++++++- src/sat/smt/euf_ackerman.h | 3 +++ src/sat/smt/euf_solver.cpp | 12 ++++++++++++ src/sat/smt/euf_solver.h | 1 + src/sat/smt/sat_th.h | 2 ++ 8 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index f5249ab31..73df52762 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -189,10 +189,10 @@ namespace euf { add_th_diseq(id, v1, v2, n->get_expr()); return; } - for (auto p : euf::enode_th_vars(r1)) { + for (auto const& p : euf::enode_th_vars(r1)) { if (!th_propagates_diseqs(p.get_id())) continue; - for (auto q : euf::enode_th_vars(r2)) + for (auto const& q : euf::enode_th_vars(r2)) if (p.get_id() == q.get_id()) add_th_diseq(p.get_id(), p.get_var(), q.get_var(), n->get_expr()); } @@ -506,7 +506,7 @@ namespace euf { void egraph::merge_th_eq(enode* n, enode* root) { SASSERT(n != root); - for (auto iv : enode_th_vars(n)) { + for (auto const& iv : enode_th_vars(n)) { theory_id id = iv.get_id(); theory_var v = root->get_th_var(id); if (v == null_theory_var) { @@ -789,7 +789,7 @@ namespace euf { out << "[b" << n->bool_var() << " := " << (n->value() == l_true ? "T":"F") << (n->merge_tf()?"":" no merge") << "] "; if (n->has_th_vars()) { out << "[t"; - for (auto v : enode_th_vars(n)) + for (auto const& v : enode_th_vars(n)) out << " " << v.get_id() << ":" << v.get_var(); out << "] "; } diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 759c85fae..76c74f93d 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -445,6 +445,7 @@ namespace arith { bool is_shared(theory_var v) const override; lbool get_phase(bool_var v) override; bool include_func_interp(func_decl* f) const override; + bool enable_ackerman_axioms(euf::enode* n) const override { return !a.is_add(n->get_expr()); } // bounds and equality propagation callbacks lp::lar_solver& lp() { return *m_solver; } diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index 1e596bec1..dbcbb36df 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -261,7 +261,8 @@ namespace array { bool is_shared(theory_var v) const override; bool enable_self_propagate() const override { return true; } void relevant_eh(euf::enode* n) override; - + bool enable_ackerman_axioms(euf::enode* n) const override { return !a.is_array(n->get_sort()); } + void merge_eh(theory_var, theory_var, theory_var v1, theory_var v2); void after_merge_eh(theory_var r1, theory_var r2, theory_var v1, theory_var v2) {} void unmerge_eh(theory_var v1, theory_var v2) {} diff --git a/src/sat/smt/euf_ackerman.cpp b/src/sat/smt/euf_ackerman.cpp index c26835f99..c8639e302 100644 --- a/src/sat/smt/euf_ackerman.cpp +++ b/src/sat/smt/euf_ackerman.cpp @@ -99,14 +99,38 @@ namespace euf { m_tmp_inference->init(m_tmp_inference); } + bool ackerman::enable_cc(app* a, app* b) { + if (!s.enable_ackerman_axioms(a)) + return false; + if (!s.enable_ackerman_axioms(b)) + return false; + for (expr* arg : *a) + if (!s.enable_ackerman_axioms(arg)) + return false; + for (expr* arg : *b) + if (!s.enable_ackerman_axioms(arg)) + return false; + return true; + } + + bool ackerman::enable_eq(expr* a, expr* b, expr* c) { + return s.enable_ackerman_axioms(a) && + s.enable_ackerman_axioms(b) && + s.enable_ackerman_axioms(c); + } + void ackerman::cg_conflict_eh(expr * n1, expr * n2) { if (!is_app(n1) || !is_app(n2)) return; + if (!s.enable_ackerman_axioms(n1)) + return; SASSERT(!s.m_drating); app* a = to_app(n1); app* b = to_app(n2); if (a->get_decl() != b->get_decl() || a->get_num_args() != b->get_num_args()) return; + if (!enable_cc(a, b)) + return; TRACE("ack", tout << "conflict eh: " << mk_pp(a, m) << " == " << mk_pp(b, m) << "\n";); insert(a, b); gc(); @@ -117,6 +141,8 @@ namespace euf { return; if (s.m_drating) return; + if (!enable_eq(a, b, c)) + return; TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << " " << mk_pp(c, m) << "\n";); insert(a, b, c); gc(); @@ -128,6 +154,8 @@ namespace euf { TRACE("ack", tout << "used cc: " << mk_pp(a, m) << " == " << mk_pp(b, m) << "\n";); SASSERT(a->get_decl() == b->get_decl()); SASSERT(a->get_num_args() == b->get_num_args()); + if (!enable_cc(a, b)) + return; insert(a, b); gc(); } @@ -173,7 +201,7 @@ namespace euf { app* b = to_app(_b); TRACE("ack", tout << mk_pp(a, m) << " " << mk_pp(b, m) << "\n";); sat::literal_vector lits; - unsigned sz = a->get_num_args(); + unsigned sz = a->get_num_args(); for (unsigned i = 0; i < sz; ++i) { expr_ref eq = s.mk_eq(a->get_arg(i), b->get_arg(i)); diff --git a/src/sat/smt/euf_ackerman.h b/src/sat/smt/euf_ackerman.h index 7b9c4c3d9..479ad2933 100644 --- a/src/sat/smt/euf_ackerman.h +++ b/src/sat/smt/euf_ackerman.h @@ -70,6 +70,9 @@ namespace euf { void add_cc(expr* a, expr* b); void add_eq(expr* a, expr* b, expr* c); void gc(); + bool enable_cc(app* a, app* b); + bool enable_eq(expr* a, expr* b, expr* c); + public: ackerman(solver& s, ast_manager& m); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index eeb195429..f6d6e73dd 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -751,6 +751,18 @@ namespace euf { } } + bool solver::enable_ackerman_axioms(expr* e) const { + euf::enode* n = get_enode(e); + if (!n) + return false; + for (auto const& thv : enode_th_vars(n)) { + auto* th = m_id2solver.get(thv.get_id(), nullptr); + if (th && !th->enable_ackerman_axioms(n)) + return false; + } + return true; + } + void solver::pre_simplify() { for (auto* e : m_solvers) e->pre_simplify(); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index dc11637b8..12afc492f 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -372,6 +372,7 @@ namespace euf { th_rewriter& get_rewriter() { return m_rewriter; } void rewrite(expr_ref& e) { m_rewriter(e); } bool is_shared(euf::enode* n) const; + bool enable_ackerman_axioms(expr* n) const; // relevancy bool m_relevancy_enabled = true; diff --git a/src/sat/smt/sat_th.h b/src/sat/smt/sat_th.h index 16138441c..9d1d9ebb1 100644 --- a/src/sat/smt/sat_th.h +++ b/src/sat/smt/sat_th.h @@ -111,6 +111,8 @@ namespace euf { virtual void new_diseq_eh(euf::th_eq const& eq) {} + virtual bool enable_ackerman_axioms(euf::enode* n) const { return true; } + virtual void relevant_eh(euf::enode* n) {} /** From 5672f5cc34c8d2342750a349a7517bc8d3c49eb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 16:40:48 -0800 Subject: [PATCH 50/88] fix #5733 --- src/model/model_core.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index da0cfb883..a23fc9800 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -111,6 +111,7 @@ void model_core::unregister_decl(func_decl * d) { m_interp[m_const_decls.back()].first = v.first; m_const_decls.pop_back(); m_interp.remove(d); + m_decls.erase(d); m.dec_ref(k); m.dec_ref(v.second); return; @@ -122,6 +123,7 @@ void model_core::unregister_decl(func_decl * d) { auto v = ef->get_data().m_value; m_finterp.remove(d); m_func_decls.erase(d); + m_decls.erase(d); m.dec_ref(k); dealloc(v); } From 42219204ed781af6971b7321607109421a198529 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 17:39:37 -0800 Subject: [PATCH 51/88] sketch replace_all --- src/ast/rewriter/seq_axioms.cpp | 72 +++++++++++++++++++++++++++++++++ src/ast/rewriter/seq_axioms.h | 2 + 2 files changed, 74 insertions(+) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index 55d58e3f7..31057313d 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -21,8 +21,11 @@ Revision History: #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" +#include "ast/recfun_decl_plugin.h" +#include "ast/rewriter/recfun_replace.h" #include "ast/rewriter/seq_axioms.h" + namespace seq { axioms::axioms(th_rewriter& r): @@ -1052,6 +1055,75 @@ namespace seq { NOT_IMPLEMENTED_YET(); } + // A basic strategy for supporting replace_all and other + // similar functions is to use recursive relations. + // Then the features for recursive functions that allow expanding definitions + // using iterative deepening can be re-used. + // + // create recursive relation 'ra' with properties: + // ra(s, p, t, r) <- s = "" && r = "" + // ra(s, p, t, r) <- s != "" && p = "" && r = t + s + // ra(s, p, t, r) <- s != "" && p + s' = s && t + r' = r && ra(s', p, t, r') + // ra(s, p, t, r) <- s = [s0] + s' && ~prefix(p, s) && r = [s0] + r' && ra(s', p, t, r') + // which amounts to: + // + // s = "" -> r = "" + // p = "" -> r = t + s + // prefix(p, s) -> p + s' = s && t + r' = r && ra(s', p, t, r') + // else -> s = [s0] + s' && r = [s0] + r' && ra(s', p, t, r') + // + // Then assert + // ra(s, p, t, replace_all(s, p, t)) + // + void axioms::replace_all_axiom(expr* r) { + expr* s = nullptr, *p = nullptr, *t = nullptr; + VERIFY(seq.str.is_replace_all(r, s, p, t)); + recfun::util rec(m); + recfun::decl::plugin& plugin = rec.get_plugin(); + recfun_replace replace(m); + sort* srt = s->get_sort(); + sort* domain[4] = { srt, srt, srt, srt }; + auto d = plugin.ensure_def(symbol("ra"), 4, domain, m.mk_bool_sort(), true); + func_decl* ra = d.get_def()->get_decl(); + var_ref vs(m.mk_var(0, srt), m); + var_ref vp(m.mk_var(1, srt), m); + var_ref vt(m.mk_var(2, srt), m); + var_ref vr(m.mk_var(3, srt), m); + var* vars[4] = { vs, vp, vt, vr }; + expr_ref test1(seq.str.mk_is_empty(vs), m); + expr_ref branch1(seq.str.mk_is_empty(vr), m); + expr_ref test2(seq.str.mk_is_empty(vp), m); + expr_ref branch2(m.mk_eq(vr, seq.str.mk_concat(vt, vs)), m); + expr_ref test3(seq.str.mk_prefix(vp, vs), m); + expr_ref s1(m_sk.mk_prefix_inv(vp, vs), m); + expr_ref r1(m_sk.mk_prefix_inv(vp, vr), m); + expr* args1[4] = { s1, vp, vt, r1 }; + expr_ref branch3(m.mk_and(m.mk_eq(seq.str.mk_concat(vp, s1), vs), + m.mk_eq(seq.str.mk_concat(vr, r1), vr), + m.mk_app(ra, 4, args1) + ), m); + expr_ref s0(m), r0(m); + m_sk.decompose(vs, s0, s1); + m_sk.decompose(vr, r0, r1); + expr* args2[4] = { s1, vp, vt, r1 }; + expr_ref branch4(m.mk_and(m.mk_eq(vs, seq.str.mk_concat(s0, s1)), + m.mk_eq(vr, seq.str.mk_concat(s0, r1)), + m.mk_app(ra, 4, args2)), m); + // s = [s0] + s' && r = [s0] + r' && ra(s', p, t, r') + + expr_ref body(m.mk_ite(test1, branch1, m.mk_ite(test2, branch2, m.mk_ite(test3, branch3, branch4))), m); + plugin.set_definition(replace, d, true, 4, vars, body); + expr* args3[4] = { s, p, t, r }; + expr_ref lit(m.mk_app(ra, 4, args3), m); + add_clause(lit); + } + + void axioms::replace_re_all_axiom(expr* e) { + expr* s = nullptr, *p = nullptr, *t = nullptr; + VERIFY(seq.str.is_replace_re_all(e, s, p, t)); + NOT_IMPLEMENTED_YET(); + } + /** diff --git a/src/ast/rewriter/seq_axioms.h b/src/ast/rewriter/seq_axioms.h index 0a2eb2ed2..583898562 100644 --- a/src/ast/rewriter/seq_axioms.h +++ b/src/ast/rewriter/seq_axioms.h @@ -107,6 +107,8 @@ namespace seq { void length_axiom(expr* n); void unroll_not_contains(expr* e); void replace_re_axiom(expr* e); + void replace_all_axiom(expr* e); + void replace_re_all_axiom(expr* e); expr_ref length_limit(expr* s, unsigned k); expr_ref is_digit(expr* ch); From 9d3c8a6a2fa489251502b548af1fe2c3cae92ef7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 17:59:31 -0800 Subject: [PATCH 52/88] na --- src/ast/rewriter/seq_axioms.cpp | 8 ++++---- src/smt/seq_axioms.h | 1 + src/smt/theory_seq.cpp | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index 31057313d..bc3b6c66e 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -1085,10 +1085,10 @@ namespace seq { sort* domain[4] = { srt, srt, srt, srt }; auto d = plugin.ensure_def(symbol("ra"), 4, domain, m.mk_bool_sort(), true); func_decl* ra = d.get_def()->get_decl(); - var_ref vs(m.mk_var(0, srt), m); - var_ref vp(m.mk_var(1, srt), m); - var_ref vt(m.mk_var(2, srt), m); - var_ref vr(m.mk_var(3, srt), m); + var_ref vs(m.mk_var(3, srt), m); + var_ref vp(m.mk_var(2, srt), m); + var_ref vt(m.mk_var(1, srt), m); + var_ref vr(m.mk_var(0, srt), m); var* vars[4] = { vs, vp, vt, vr }; expr_ref test1(seq.str.mk_is_empty(vs), m); expr_ref branch1(seq.str.mk_is_empty(vr), m); diff --git a/src/smt/seq_axioms.h b/src/smt/seq_axioms.h index e9fc3cb53..525f6b3db 100644 --- a/src/smt/seq_axioms.h +++ b/src/smt/seq_axioms.h @@ -73,6 +73,7 @@ namespace smt { void add_indexof_axiom(expr* n) { m_ax.indexof_axiom(n); } void add_last_indexof_axiom(expr* n) { m_ax.last_indexof_axiom(n); } void add_replace_axiom(expr* n) { m_ax.replace_axiom(n); } + void add_replace_all_axiom(expr* n) { m_ax.replace_all_axiom(n); } void add_at_axiom(expr* n) { m_ax.at_axiom(n); } void add_nth_axiom(expr* n) { m_ax.nth_axiom(n); } void add_itos_axiom(expr* n) { m_ax.itos_axiom(n); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 5ef415d6a..c86db1aa5 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -2646,6 +2646,9 @@ void theory_seq::deque_axiom(expr* n) { else if (m_util.str.is_replace(n)) { m_ax.add_replace_axiom(n); } + else if (m_util.str.is_replace_all(n)) { + m_ax.add_replace_all_axiom(n); + } else if (m_util.str.is_extract(n)) { m_ax.add_extract_axiom(n); } @@ -3190,6 +3193,7 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_to_code(n) || m_util.str.is_unit(n) || m_util.str.is_length(n) || + /* m_util.str.is_replace_all(n) || uncomment to enable axiomatization */ m_util.str.is_le(n)) { enque_axiom(n); } From 8245935d41c3f11db4b00cafd43ccc680edaa18e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 20:33:17 -0800 Subject: [PATCH 53/88] #5641 add handlers for basic set operations to euf=true --- src/ast/array_decl_plugin.h | 9 ++++++ src/sat/smt/array_axioms.cpp | 47 ++++++++++++++++++++++++------- src/sat/smt/array_internalize.cpp | 28 ++++++++++++------ src/sat/smt/array_solver.cpp | 2 +- src/sat/smt/array_solver.h | 4 ++- 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index f986eb46a..0800b6af3 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -150,6 +150,10 @@ public: bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); } bool is_ext(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_EXT); } bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); } + bool is_union(expr* n) const { return is_app_of(n, m_fid, OP_SET_UNION); } + bool is_intersect(expr* n) const { return is_app_of(n, m_fid, OP_SET_INTERSECT); } + bool is_difference(expr* n) const { return is_app_of(n, m_fid, OP_SET_DIFFERENCE); } + bool is_complement(expr* n) const { return is_app_of(n, m_fid, OP_SET_COMPLEMENT); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); } bool is_set_has_size(expr* e) const { return is_app_of(e, m_fid, OP_SET_HAS_SIZE); } @@ -158,11 +162,14 @@ public: bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); } bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); } bool is_map(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_MAP); } + bool is_union(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_UNION); } + bool is_intersect(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_INTERSECT); } bool is_as_array(func_decl* f) const { return is_decl_of(f, m_fid, OP_AS_ARRAY); } bool is_set_has_size(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_HAS_SIZE); } bool is_set_card(func_decl* f) const { return is_decl_of(f, m_fid, OP_SET_CARD); } bool is_default(func_decl* f) const { return is_decl_of(f, m_fid, OP_ARRAY_DEFAULT); } bool is_default(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_DEFAULT); } + bool is_subset(expr const* n) const { return is_app_of(n, m_fid, OP_SET_SUBSET); } bool is_as_array(func_decl* f, func_decl*& g) const { return is_decl_of(f, m_fid, OP_AS_ARRAY) && (g = get_as_array_func_decl(f), true); } func_decl * get_as_array_func_decl(expr * n) const; func_decl * get_as_array_func_decl(func_decl* f) const; @@ -172,6 +179,8 @@ public: bool is_const(expr* e, expr*& v) const; bool is_store_ext(expr* e, expr_ref& a, expr_ref_vector& args, expr_ref& value); + + MATCH_BINARY(is_subset); }; class array_util : public array_recognizers { diff --git a/src/sat/smt/array_axioms.cpp b/src/sat/smt/array_axioms.cpp index b4ab89d1f..296c35b8c 100644 --- a/src/sat/smt/array_axioms.cpp +++ b/src/sat/smt/array_axioms.cpp @@ -84,7 +84,7 @@ namespace array { return assert_default_const_axiom(to_app(child)); else if (a.is_store(child)) return assert_default_store_axiom(to_app(child)); - else if (a.is_map(child)) + else if (is_map_combinator(child)) return assert_default_map_axiom(to_app(child)); else return false; @@ -115,7 +115,7 @@ namespace array { return assert_select_as_array_axiom(select, to_app(child)); else if (a.is_store(child)) return assert_select_store_axiom(select, to_app(child)); - else if (a.is_map(child)) + else if (is_map_combinator(child)) return assert_select_map_axiom(select, to_app(child)); else if (is_lambda(child)) return assert_select_lambda_axiom(select, child); @@ -273,16 +273,19 @@ namespace array { return add_clause(lit1, ~lit2); } + bool solver::is_map_combinator(expr* map) const { + return a.is_map(map) || a.is_union(map) || a.is_intersect(map) || a.is_difference(map) || a.is_complement(map); + } + /** * Assert axiom: * select(map[f](a, ... d), i) = f(select(a,i),...,select(d,i)) */ bool solver::assert_select_map_axiom(app* select, app* map) { ++m_stats.m_num_select_map_axiom; - SASSERT(a.is_map(map)); SASSERT(a.is_select(select)); + SASSERT(is_map_combinator(map)); SASSERT(map->get_num_args() > 0); - func_decl* f = a.get_map_func_decl(map); unsigned num_args = select->get_num_args(); ptr_buffer args1, args2; vector > args2l; @@ -303,7 +306,8 @@ namespace array { expr_ref sel1(m), sel2(m); sel1 = a.mk_select(args1); - sel2 = m.mk_app(f, args2); + sel2 = apply_map(map, args2.size(), args2.data()); + rewrite(sel2); euf::enode* n1 = e_internalize(sel1); euf::enode* n2 = e_internalize(sel2); @@ -330,21 +334,44 @@ namespace array { return ctx.propagate(n1, n2, array_axiom()); } + expr_ref solver::apply_map(app* map, unsigned n, expr* const* args) { + expr_ref result(m); + if (a.is_map(map)) + result = m.mk_app(a.get_map_func_decl(map), n, args); + else if (a.is_union(map)) + result = m.mk_or(n, args); + else if (a.is_intersect(map)) + result = m.mk_and(n, args); + else if (a.is_difference(map)) { + SASSERT(n > 0); + result = args[0]; + for (unsigned i = 1; i < n; ++i) + result = m.mk_and(result, m.mk_not(args[i])); + } + else if (a.is_complement(map)) { + SASSERT(n == 1); + result = m.mk_not(args[0]); + } + else { + UNREACHABLE(); + } + rewrite(result); + return result; + } + + /** * Assert: * default(map[f](a,..,d)) = f(default(a),..,default(d)) */ bool solver::assert_default_map_axiom(app* map) { ++m_stats.m_num_default_map_axiom; - SASSERT(a.is_map(map)); - func_decl* f = a.get_map_func_decl(map); - SASSERT(map->get_num_args() == f->get_arity()); + SASSERT(is_map_combinator(map)); expr_ref_vector args2(m); for (expr* arg : *map) args2.push_back(a.mk_default(arg)); expr_ref def1(a.mk_default(map), m); - expr_ref def2(m.mk_app(f, args2), m); - rewrite(def2); + expr_ref def2 = apply_map(map, args2.size(), args2.data()); return ctx.propagate(e_internalize(def1), e_internalize(def2), array_axiom()); } diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 5e285112d..b7b79ddbc 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -117,15 +117,24 @@ namespace array { add_parent_default(find(n->get_arg(0)), n); break; case OP_ARRAY_MAP: - for (auto* arg : euf::enode_args(n)) - add_parent_lambda(find(arg), n); - internalize_lambda_eh(n); - break; case OP_SET_UNION: case OP_SET_INTERSECT: case OP_SET_DIFFERENCE: case OP_SET_COMPLEMENT: - case OP_SET_SUBSET: + for (auto* arg : euf::enode_args(n)) + add_parent_lambda(find(arg), n); + internalize_lambda_eh(n); + break; + case OP_SET_SUBSET: { + expr* x, *y; + VERIFY(a.is_subset(n->get_expr(), x, y)); + expr_ref diff(a.mk_setminus(x, y), m); + expr_ref emp(a.mk_empty_set(x->get_sort()), m); + sat::literal eq = eq_internalize(diff, emp); + sat::literal sub = expr2literal(n->get_expr()); + add_equiv(eq, sub); + break; + } case OP_SET_HAS_SIZE: case OP_SET_CARD: ctx.unhandled_function(n->get_decl()); @@ -163,15 +172,16 @@ namespace array { set_prop_upward(find(n->get_arg(0))); break; case OP_ARRAY_MAP: - for (auto* arg : euf::enode_args(n)) - set_prop_upward_store(arg); - set_prop_upward(find(n)); - break; case OP_SET_UNION: case OP_SET_INTERSECT: case OP_SET_DIFFERENCE: case OP_SET_COMPLEMENT: + for (auto* arg : euf::enode_args(n)) + set_prop_upward_store(arg); + set_prop_upward(find(n)); + break; case OP_SET_SUBSET: + break; case OP_SET_HAS_SIZE: case OP_SET_CARD: ctx.unhandled_function(n->get_decl()); diff --git a/src/sat/smt/array_solver.cpp b/src/sat/smt/array_solver.cpp index f3414a4c6..f2836d9aa 100644 --- a/src/sat/smt/array_solver.cpp +++ b/src/sat/smt/array_solver.cpp @@ -275,6 +275,6 @@ namespace array { } bool solver::can_beta_reduce(expr* c) const { - return a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c) || a.is_map(c); + return a.is_const(c) || a.is_as_array(c) || a.is_store(c) || is_lambda(c) || is_map_combinator(c); } } diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index dbcbb36df..1c2935c99 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -181,7 +181,9 @@ namespace array { bool assert_congruent_axiom(expr* e1, expr* e2); bool add_delayed_axioms(); bool add_as_array_eqs(euf::enode* n); - + expr_ref apply_map(app* map, unsigned n, expr* const* args); + bool is_map_combinator(expr* e) const; + bool has_unitary_domain(app* array_term); bool has_large_domain(expr* array_term); std::pair mk_epsilon(sort* s); From 5cd1fe31fdd12954d7c8d92daa420cd1d1a4fe0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jan 2022 20:37:26 -0800 Subject: [PATCH 54/88] propagate parent default not add parent default) Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_internalize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index b7b79ddbc..683cc5d07 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -163,8 +163,8 @@ namespace array { break; case OP_CONST_ARRAY: case OP_AS_ARRAY: - set_prop_upward(find(n)); - add_parent_default(find(n), n); + set_prop_upward(find(n)); + propagate_parent_default(find(n)); break; case OP_ARRAY_EXT: break; From 543c16c73e4a1da5f43a6a434f83bb137126819e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 10:22:51 -0800 Subject: [PATCH 55/88] Trace unexpected exceptions in or-else code #5746 --- src/tactic/tactical.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index fca2f8481..e6a3a024e 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -336,6 +336,21 @@ public: catch (tactic_exception &) { result.reset(); } + catch (z3_error & ex) { + IF_VERBOSE(10, verbose_stream() << "z3 error: " << ex.error_code() << " in or-else\n"); + throw; + } + catch (z3_exception& ex) { + IF_VERBOSE(10, verbose_stream() << ex.msg() << " in or-else\n"); + throw; + } + catch (...) { + IF_VERBOSE(10, verbose_stream() << " unclassified exception in or-else\n"); + // std::current_exception returns a std::exception_ptr, which apparently + // needs to be re-thrown to extract type information. + // typeid(ex).name() would be nice. + throw; + } } else { t->operator()(in, result); From 88707f37e75c3c1d8fd54570af8da7135b3bfa2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 11:31:50 -0800 Subject: [PATCH 56/88] Better error reporting #5746 --- src/api/api_solver.cpp | 5 ++++- src/tactic/tactical.cpp | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 8e8360cd3..43093d749 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -607,7 +607,10 @@ extern "C" { return Z3_L_UNDEF; } catch (...) { - to_solver_ref(s)->set_reason_unknown(eh); + if (eh.caller_id() == event_handler_caller_t::UNSET_EH_CALLER) + to_solver_ref(s)->set_reason_unknown("unclassified exception"); + else + to_solver_ref(s)->set_reason_unknown(eh); to_solver(s)->set_eh(nullptr); return Z3_L_UNDEF; } diff --git a/src/tactic/tactical.cpp b/src/tactic/tactical.cpp index e6a3a024e..c5a9e6984 100644 --- a/src/tactic/tactical.cpp +++ b/src/tactic/tactical.cpp @@ -344,6 +344,10 @@ public: IF_VERBOSE(10, verbose_stream() << ex.msg() << " in or-else\n"); throw; } + catch (const std::exception &ex) { + IF_VERBOSE(10, verbose_stream() << ex.what() << " in or-else\n"); + throw; + } catch (...) { IF_VERBOSE(10, verbose_stream() << " unclassified exception in or-else\n"); // std::current_exception returns a std::exception_ptr, which apparently From e84ddb0d9a9f52bb4b5cfbdb5acde4c81ae8e071 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 11:33:21 -0800 Subject: [PATCH 57/88] more #5746 --- src/api/api_solver.cpp | 5 +---- src/solver/check_sat_result.cpp | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 43093d749..8e8360cd3 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -607,10 +607,7 @@ extern "C" { return Z3_L_UNDEF; } catch (...) { - if (eh.caller_id() == event_handler_caller_t::UNSET_EH_CALLER) - to_solver_ref(s)->set_reason_unknown("unclassified exception"); - else - to_solver_ref(s)->set_reason_unknown(eh); + to_solver_ref(s)->set_reason_unknown(eh); to_solver(s)->set_eh(nullptr); return Z3_L_UNDEF; } diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index b772f21ae..71bd24747 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -20,7 +20,9 @@ Notes: void check_sat_result::set_reason_unknown(event_handler& eh) { switch (eh.caller_id()) { - case UNSET_EH_CALLER: break; + case UNSET_EH_CALLER: + set_reason_unknown("unclassifed exception"); + break; case CTRL_C_EH_CALLER: set_reason_unknown("interrupted from keyboard"); break; From 0ca5e7207ea3433f7fc5dd76da0604396a55d97a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 11:35:55 -0800 Subject: [PATCH 58/88] #5746 --- src/solver/check_sat_result.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/solver/check_sat_result.cpp b/src/solver/check_sat_result.cpp index 71bd24747..d29e0f2bd 100644 --- a/src/solver/check_sat_result.cpp +++ b/src/solver/check_sat_result.cpp @@ -21,7 +21,8 @@ Notes: void check_sat_result::set_reason_unknown(event_handler& eh) { switch (eh.caller_id()) { case UNSET_EH_CALLER: - set_reason_unknown("unclassifed exception"); + if (reason_unknown() == "") + set_reason_unknown("unclassifed exception"); break; case CTRL_C_EH_CALLER: set_reason_unknown("interrupted from keyboard"); From d0fb3cba1574a4ce561b962fa07b19f104c59178 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 17:45:43 -0800 Subject: [PATCH 59/88] #5641 - projection that skips interpreted functions can violate model evaluation. --- src/qe/mbp/mbp_arith.cpp | 47 +++++++++++++++++++---------------- src/qe/mbp/mbp_arith.h | 4 +-- src/qe/mbp/mbp_arrays.cpp | 4 +-- src/qe/mbp/mbp_arrays.h | 2 +- src/qe/mbp/mbp_datatypes.cpp | 4 +-- src/qe/mbp/mbp_datatypes.h | 2 +- src/qe/mbp/mbp_plugin.h | 4 +-- src/qe/qe_mbi.cpp | 5 +++- src/sat/smt/q_mbi.cpp | 8 +++--- src/sat/smt/q_model_fixer.cpp | 2 +- 10 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 120931536..377b62ac0 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -249,8 +249,8 @@ namespace mbp { bool operator()(model& model, app* v, app_ref_vector& vars, expr_ref_vector& lits) { app_ref_vector vs(m); vs.push_back(v); - project(model, vs, lits, false); - return vs.empty(); + vector defs; + return project(model, vs, lits, defs, false) && vs.empty(); } typedef opt::model_based_opt::var var; @@ -265,12 +265,12 @@ namespace mbp { return t; } - vector project(model& model, app_ref_vector& vars, expr_ref_vector& fmls, bool compute_def) { + bool project(model& model, app_ref_vector& vars, expr_ref_vector& fmls, vector& result, bool compute_def) { bool has_arith = false; for (expr* v : vars) has_arith |= is_arith(v); if (!has_arith) - return vector(); + return true; model_evaluator eval(model); TRACE("qe", tout << model;); eval.set_model_completion(true); @@ -294,7 +294,7 @@ namespace mbp { } fmls.shrink(j); TRACE("qe", tout << "formulas\n" << fmls << "\n"; - for (auto [e, id] : tids) + for (auto const& [e, id] : tids) tout << mk_pp(e, m) << " -> " << id << "\n";); // fmls holds residue, @@ -312,7 +312,7 @@ namespace mbp { rational r; expr_ref val = eval(v); if (!m.inc()) - return vector(); + return false; if (!a.is_numeral(val, r)) throw default_exception("evaluation did not produce a numeral"); TRACE("qe", tout << mk_pp(v, m) << " " << val << "\n";); @@ -326,15 +326,13 @@ namespace mbp { if (is_arith(e) && !var_mark.is_marked(e)) mark_rec(fmls_mark, e); } - if (m_check_purified) { for (expr* fml : fmls) mark_rec(fmls_mark, fml); for (auto& kv : tids) { expr* e = kv.m_key; - if (!var_mark.is_marked(e)) { - mark_rec(fmls_mark, e); - } + if (!var_mark.is_marked(e)) + mark_rec(fmls_mark, e); } } @@ -364,16 +362,18 @@ namespace mbp { for (auto const& d : defs) tout << "def: " << d << "\n"; tout << fmls << "\n";); - vector result; if (compute_def) optdefs2mbpdef(defs, index2expr, real_vars, result); - if (m_apply_projection) - apply_projection(result, fmls); + if (m_apply_projection && !apply_projection(eval, result, fmls)) + return false; + TRACE("qe", - for (auto [v, t] : result) + for (auto const& [v, t] : result) tout << v << " := " << t << "\n"; + for (auto* f : fmls) + tout << mk_pp(f, m) << " := " << eval(f) << "\n"; tout << "fmls:" << fmls << "\n";); - return result; + return true; } void optdefs2mbpdef(vector const& defs, ptr_vector const& index2expr, unsigned_vector const& real_vars, vector& result) { @@ -548,10 +548,11 @@ namespace mbp { } } - void apply_projection(vector& defs, expr_ref_vector& fmls) { + bool apply_projection(model_evaluator& eval, vector const& defs, expr_ref_vector& fmls) { if (fmls.empty() || defs.empty()) - return; + return true; expr_safe_replace subst(m); + expr_ref_vector fmls_tmp(m); expr_ref tmp(m); for (unsigned i = defs.size(); i-- > 0; ) { auto const& d = defs[i]; @@ -561,8 +562,11 @@ namespace mbp { unsigned j = 0; for (expr* fml : fmls) { subst(fml, tmp); + if (m.is_false(eval(tmp))) + return false; fmls[j++] = tmp; } + return true; } }; @@ -579,12 +583,13 @@ namespace mbp { return (*m_imp)(model, var, vars, lits); } - void arith_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - m_imp->project(model, vars, lits, false); + bool arith_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + vector defs; + return m_imp->project(model, vars, lits, defs, false); } - vector arith_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return m_imp->project(model, vars, lits, true); + bool arith_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) { + return m_imp->project(model, vars, lits, defs, true); } void arith_project_plugin::set_check_purified(bool check_purified) { diff --git a/src/qe/mbp/mbp_arith.h b/src/qe/mbp/mbp_arith.h index 51d80a870..ca4cccb74 100644 --- a/src/qe/mbp/mbp_arith.h +++ b/src/qe/mbp/mbp_arith.h @@ -29,8 +29,8 @@ namespace mbp { bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override { return false; } family_id get_family_id() override; - void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; - vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + bool operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) override; void saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) override { UNREACHABLE(); } opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt); diff --git a/src/qe/mbp/mbp_arrays.cpp b/src/qe/mbp/mbp_arrays.cpp index 149d11987..0f4c805b7 100644 --- a/src/qe/mbp/mbp_arrays.cpp +++ b/src/qe/mbp/mbp_arrays.cpp @@ -1624,8 +1624,8 @@ namespace mbp { ); } - vector array_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return vector(); + bool array_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) { + return true; } void array_project_plugin::saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) { diff --git a/src/qe/mbp/mbp_arrays.h b/src/qe/mbp/mbp_arrays.h index bb18cde11..7dd904108 100644 --- a/src/qe/mbp/mbp_arrays.h +++ b/src/qe/mbp/mbp_arrays.h @@ -35,7 +35,7 @@ namespace mbp { bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; void operator()(model& model, app_ref_vector& vars, expr_ref& fml, app_ref_vector& aux_vars, bool reduce_all_selects); family_id get_family_id() override; - vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) override; void saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) override; }; diff --git a/src/qe/mbp/mbp_datatypes.cpp b/src/qe/mbp/mbp_datatypes.cpp index 798258599..e40a19546 100644 --- a/src/qe/mbp/mbp_datatypes.cpp +++ b/src/qe/mbp/mbp_datatypes.cpp @@ -300,8 +300,8 @@ namespace mbp { return m_imp->solve(model, vars, lits); } - vector datatype_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { - return vector(); + bool datatype_project_plugin::project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) { + return true; } void datatype_project_plugin::saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) { diff --git a/src/qe/mbp/mbp_datatypes.h b/src/qe/mbp/mbp_datatypes.h index 345260970..f30aaaa9f 100644 --- a/src/qe/mbp/mbp_datatypes.h +++ b/src/qe/mbp/mbp_datatypes.h @@ -34,7 +34,7 @@ namespace mbp { bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) override; bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; family_id get_family_id() override; - vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) override; + bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) override; void saturate(model& model, func_decl_ref_vector const& shared, expr_ref_vector& lits) override; }; diff --git a/src/qe/mbp/mbp_plugin.h b/src/qe/mbp/mbp_plugin.h index 741639aaa..12b592960 100644 --- a/src/qe/mbp/mbp_plugin.h +++ b/src/qe/mbp/mbp_plugin.h @@ -67,7 +67,7 @@ namespace mbp { virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; } virtual family_id get_family_id() { return null_family_id; } - virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; + virtual bool operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return false; }; /** \brief project vars modulo model, return set of definitions for eliminated variables. @@ -76,7 +76,7 @@ namespace mbp { - returns set of definitions (TBD: in triangular form, the last definition can be substituted into definitions that come before) */ - virtual vector project(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return vector(); } + virtual bool project(model& model, app_ref_vector& vars, expr_ref_vector& lits, vector& defs) { return true; } /** \brief model based saturation. Saturates theory axioms to equi-satisfiable literals over EUF, diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 1dcbb178f..5d00d8a6b 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -266,7 +266,10 @@ namespace qe { vector uflia_mbi::arith_project(model_ref& mdl, app_ref_vector& avars, expr_ref_vector& lits) { mbp::arith_project_plugin ap(m); ap.set_check_purified(false); - return ap.project(*mdl.get(), avars, lits); + vector defs; + bool ok = ap.project(*mdl.get(), avars, lits, defs); + CTRACE("qe", !ok, tout << "projection failure ignored!!!!\n"); + return defs; } mbi_result uflia_mbi::operator()(expr_ref_vector& lits, model_ref& mdl) { diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 000937700..38e8ff45e 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -67,7 +67,7 @@ namespace q { } } m_max_cex += ctx.get_config().m_mbqi_max_cexs; - for (auto [qlit, fml, generation] : m_instantiations) { + for (auto const& [qlit, fml, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ctx.mk_literal(fml); m_qs.add_clause(~qlit, ~lit); @@ -308,8 +308,10 @@ namespace q { proj.extract_literals(*m_model, vars, fmls); fmls_extracted = true; } - if (p) - (*p)(*m_model, vars, fmls); + if (!p) + continue; + if (!(*p)(*m_model, vars, fmls)) + return expr_ref(nullptr, m); } for (app* v : vars) { expr_ref term(m); diff --git a/src/sat/smt/q_model_fixer.cpp b/src/sat/smt/q_model_fixer.cpp index a87bf3397..456525c42 100644 --- a/src/sat/smt/q_model_fixer.cpp +++ b/src/sat/smt/q_model_fixer.cpp @@ -256,7 +256,7 @@ namespace q { tout << "invert-app " << mk_pp(t, m) << " = " << mk_pp(value, m) << "\n"; if (v2r.find(value, r)) tout << "inverse " << mk_pp(r->get_expr(), m) << "\n"; - ctx.display(tout); + /*ctx.display(tout); */ ); if (v2r.find(value, r)) return r->get_expr(); From 43e449a80539f52f569b397f87874f44321ffd44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 17:53:26 -0800 Subject: [PATCH 60/88] #5641 --- src/sat/smt/q_mbi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 38e8ff45e..d63ca2420 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -129,7 +129,7 @@ namespace q { r = n; } else if (n->generation() == gen) { - if ((++count) % m_qs.random() == 0) + if ((++count) % (1 + m_qs.random()) == 0) r = n; } if (count > m_max_choose_candidates) From 9cbec3b0caa41f79129afe10baf5fcc5570cdfae Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 19:15:23 -0800 Subject: [PATCH 61/88] #5641 Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_mbi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index d63ca2420..8589dfc6d 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -129,7 +129,7 @@ namespace q { r = n; } else if (n->generation() == gen) { - if ((++count) % (1 + m_qs.random()) == 0) + if ((m_qs.random() % ++count) == 0) r = n; } if (count > m_max_choose_candidates) From a71aa113e0eb03fd5dcedf33ab2d0ef53a9e8085 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 19:36:17 -0800 Subject: [PATCH 62/88] #5641 Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 11 +++++++++++ src/sat/smt/arith_solver.cpp | 35 ++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 399aa76f2..d229865ad 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -273,6 +273,17 @@ public: bool is_rem0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_REM0); } bool is_mod0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_MOD0); } bool is_power0(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_POWER0); } + bool is_power(func_decl const * n) const { return is_decl_of(n, arith_family_id, OP_POWER); } + bool is_add(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_ADD); } + bool is_mul(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_MUL); } + bool is_sub(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_SUB); } + bool is_uminus(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_UMINUS); } + bool is_div(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_DIV); } + bool is_rem(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_REM); } + bool is_mod(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_MOD); } + bool is_to_real(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_TO_REAL); } + bool is_to_int(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_TO_INT); } + bool is_is_int(func_decl const* f) const { return is_decl_of(f, arith_family_id, OP_IS_INT); } bool is_add(expr const * n) const { return is_app_of(n, arith_family_id, OP_ADD); } bool is_sub(expr const * n) const { return is_app_of(n, arith_family_id, OP_SUB); } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 19be6d9d5..1fa0606c2 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1447,21 +1447,19 @@ namespace arith { TRACE("arith", tout << "canceled\n";); return l_undef; } - if (!m_nla) { - TRACE("arith", tout << "no nla\n";); + CTRACE("arith", !m_nla, tout << "no nla\n";); + if (!m_nla) return l_true; - } if (!m_nla->need_check()) return l_true; m_a1 = nullptr; m_a2 = nullptr; lbool r = m_nla->check(m_nla_lemma_vector); switch (r) { - case l_false: { + case l_false: for (const nla::lemma& l : m_nla_lemma_vector) false_case_of_check_nla(l); break; - } case l_true: if (assume_eqs()) return l_false; @@ -1478,11 +1476,26 @@ namespace arith { } bool solver::include_func_interp(func_decl* f) const { - return - a.is_div0(f) || - a.is_idiv0(f) || - a.is_power0(f) || - a.is_rem0(f) || - a.is_mod0(f); + SASSERT(f->get_family_id() == get_id()); + switch (f->get_decl_kind()) { + case OP_ADD: + case OP_SUB: + case OP_UMINUS: + case OP_MUL: + case OP_LE: + case OP_LT: + case OP_GE: + case OP_GT: + case OP_MOD: + case OP_REM: + case OP_DIV: + case OP_POWER: + case OP_IS_INT: + case OP_TO_INT: + case OP_TO_REAL: + return false; + default: + return true; + } } } From da154b2f7ef2cd9b4e71dcca36cf78ec3216c03c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jan 2022 19:44:20 -0800 Subject: [PATCH 63/88] disable macos with ocaml as it fails too often Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0057add97..bff70c859 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -288,6 +288,7 @@ jobs: - job: "MacOSOCaml" displayName: "MacOS build with OCaml" + condition: eq(0,1) pool: vmImage: "macOS-latest" steps: From cf08cdff9c62b8db2805dbd9c4935ccb9569f08d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 08:54:54 -0800 Subject: [PATCH 64/88] #5747 --- src/api/python/z3/z3.py | 4 ++++ src/sat/smt/arith_solver.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index a11061970..2b0286608 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8789,6 +8789,10 @@ def Product(*args): _args, sz = _to_ast_array(args) return ArithRef(Z3_mk_mul(ctx.ref(), sz, _args), ctx) +def Abs(arg): + """Create the absolute value of an arithmetic expression""" + return If(arg > 0, arg, -arg) + def AtMost(*args): """Create an at-most Pseudo-Boolean k constraint. diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 1fa0606c2..80dea338a 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1489,6 +1489,7 @@ namespace arith { case OP_MOD: case OP_REM: case OP_DIV: + case OP_IDIV: case OP_POWER: case OP_IS_INT: case OP_TO_INT: From 29444498846580bc8b87ae11529f303191ea727c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 11:12:09 -0800 Subject: [PATCH 65/88] #5641 --- src/sat/sat_solver.cpp | 22 +++++++++++----------- src/sat/sat_solver.h | 2 +- src/sat/tactic/goal2sat.cpp | 6 ++++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 51f2c3d98..286038dea 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -288,6 +288,7 @@ namespace sat { m_free_vars.pop_back(); m_active_vars.push_back(v); reset_var(v, ext, dvar); + SASSERT(v < m_justification.size()); return v; } m_active_vars.push_back(v); @@ -3508,7 +3509,6 @@ namespace sat { unsigned old_num_vars = m_vars_lim.pop(num_scopes); if (old_num_vars == m_active_vars.size()) return; - unsigned free_vars_head = m_free_vars.size(); unsigned sz = m_active_vars.size(), j = old_num_vars; unsigned new_lvl = m_scopes.size() - num_scopes; @@ -3538,9 +3538,7 @@ namespace sat { } else { set_eliminated(v, true); - if (!is_external(v) || true) { - m_free_vars.push_back(v); - } + m_vars_to_free.push_back(v); } } m_active_vars.shrink(j); @@ -3550,8 +3548,7 @@ namespace sat { IF_VERBOSE(0, verbose_stream() << "cleanup: " << lit << " " << w.is_binary_clause() << "\n"); } }; - for (unsigned i = m_free_vars.size(); i-- > free_vars_head; ) { - bool_var v = m_free_vars[i]; + for (bool_var v : m_vars_to_free) { cleanup_watch(literal(v, false)); cleanup_watch(literal(v, true)); @@ -3560,7 +3557,7 @@ namespace sat { tout << "clauses to reinit: " << (m_clauses_to_reinit.size() - old_sz) << "\n"; tout << "new level: " << new_lvl << "\n"; tout << "vars to reinit: " << m_vars_to_reinit << "\n"; - tout << "free vars: " << bool_var_vector(m_free_vars.size() - free_vars_head, m_free_vars.data() + free_vars_head) << "\n"; + tout << "free vars: " << bool_var_vector(m_vars_to_free) << "\n"; for (unsigned i = m_clauses_to_reinit.size(); i-- > old_sz; ) tout << "reinit: " << m_clauses_to_reinit[i] << "\n"; display(tout);); @@ -3599,7 +3596,6 @@ namespace sat { void solver::pop(unsigned num_scopes) { if (num_scopes == 0) return; - unsigned free_vars_head = m_free_vars.size(); if (m_ext) { pop_vars(num_scopes); m_ext->pop(num_scopes); @@ -3609,13 +3605,16 @@ namespace sat { scope & s = m_scopes[new_lvl]; m_inconsistent = false; // TBD: use model seems to make this redundant: s.m_inconsistent; unassign_vars(s.m_trail_lim, new_lvl); - for (unsigned i = m_free_vars.size(); i-- > free_vars_head; ) - m_case_split_queue.del_var_eh(m_free_vars[i]); + for (bool_var v : m_vars_to_free) + m_case_split_queue.del_var_eh(v); m_scope_lvl -= num_scopes; reinit_clauses(s.m_clauses_to_reinit_lim); m_scopes.shrink(new_lvl); - if (m_ext) + if (m_ext) { m_ext->pop_reinit(); + m_free_vars.append(m_vars_to_free); + m_vars_to_free.reset(); + } } void solver::unassign_vars(unsigned old_sz, unsigned new_lvl) { @@ -3692,6 +3691,7 @@ namespace sat { // void solver::user_push() { + pop_to_base_level(); m_free_var_freeze.push_back(m_free_vars); m_free_vars.reset(); // resetting free_vars forces new variables to be assigned above new_v diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index c4e38fb06..f6cc881b5 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -124,7 +124,7 @@ namespace sat { clause_vector m_clauses; clause_vector m_learned; unsigned m_num_frozen; - unsigned_vector m_active_vars, m_free_vars, m_vars_to_reinit; + unsigned_vector m_active_vars, m_free_vars, m_vars_to_free, m_vars_to_reinit; vector m_watches; svector m_assignment; svector m_justification; diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index bdb37bc79..1db0c08fe 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -224,6 +224,7 @@ struct goal2sat::imp : public sat::sat_internalizer { } sat::bool_var add_bool_var(expr* t) override { + force_push(); sat::bool_var v = m_map.to_bool_var(t); if (v == sat::null_bool_var) v = mk_bool_var(t); @@ -239,10 +240,11 @@ struct goal2sat::imp : public sat::sat_internalizer { m_map.push(); m_cache_lim.push_back(m_cache_trail.size()); } + } } void push() override { - ++m_num_scopes; + ++m_num_scopes; } void pop(unsigned n) override { @@ -263,7 +265,7 @@ struct goal2sat::imp : public sat::sat_internalizer { } } m_cache_trail.shrink(k); - m_cache_lim.shrink(m_cache_lim.size() - n); + m_cache_lim.shrink(m_cache_lim.size() - n); } // remove non-external literals from cache. From 1f964eea904da78b8ad85368fd2ee30319c1b9fb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 11:12:28 -0800 Subject: [PATCH 66/88] na --- src/sat/tactic/goal2sat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 1db0c08fe..e3386b4e2 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -239,7 +239,6 @@ struct goal2sat::imp : public sat::sat_internalizer { for (; m_num_scopes > 0; --m_num_scopes) { m_map.push(); m_cache_lim.push_back(m_cache_trail.size()); - } } } From 8e3185ffe3cc54ba5387b077d30852e5ccd3c113 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 14:08:01 -0800 Subject: [PATCH 67/88] remove dual solver approach Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_axioms.cpp | 30 +++-- src/sat/sat_solver.cpp | 2 +- src/sat/smt/CMakeLists.txt | 2 - src/sat/smt/euf_internalize.cpp | 4 +- src/sat/smt/euf_relevancy.cpp | 208 -------------------------------- src/sat/smt/euf_solver.cpp | 18 +-- src/sat/smt/euf_solver.h | 27 ++--- src/sat/smt/sat_dual_solver.cpp | 189 ----------------------------- src/sat/smt/sat_dual_solver.h | 84 ------------- src/sat/smt/smt_relevant.cpp | 6 +- src/sat/smt/smt_relevant.h | 2 +- src/sat/tactic/goal2sat.cpp | 8 -- src/sat/tactic/sat_tactic.cpp | 1 + 13 files changed, 44 insertions(+), 537 deletions(-) delete mode 100644 src/sat/smt/euf_relevancy.cpp delete mode 100644 src/sat/smt/sat_dual_solver.cpp delete mode 100644 src/sat/smt/sat_dual_solver.h diff --git a/src/ast/rewriter/seq_axioms.cpp b/src/ast/rewriter/seq_axioms.cpp index bc3b6c66e..ab19a5586 100644 --- a/src/ast/rewriter/seq_axioms.cpp +++ b/src/ast/rewriter/seq_axioms.cpp @@ -1061,16 +1061,12 @@ namespace seq { // using iterative deepening can be re-used. // // create recursive relation 'ra' with properties: - // ra(s, p, t, r) <- s = "" && r = "" - // ra(s, p, t, r) <- s != "" && p = "" && r = t + s - // ra(s, p, t, r) <- s != "" && p + s' = s && t + r' = r && ra(s', p, t, r') - // ra(s, p, t, r) <- s = [s0] + s' && ~prefix(p, s) && r = [s0] + r' && ra(s', p, t, r') + // ra(i, j, s, p, t, r) <- len(s) = i && len(r) = j + // ra(i, j, s, p, t, r) <- len(s) > i = 0 && p = "" && r = t + s + // ra(i, j, s, p, t, r) <- len(s) > i && p != "" && s = extract(s, 0, i) + p + extract(s, i + len(p), len(s)) && r = extract(r, 0, i) + t + extract(r, i + len(p), len(r)) && ra(i + len(p), j + len(t), s, p, t, r) + // ra(i, s, p, t, r) <- ~prefix(p, extract(s, i, len(s)) && at(s,i) = at(r,j) && ra(i + 1, j + 1, s, p, t, r) // which amounts to: // - // s = "" -> r = "" - // p = "" -> r = t + s - // prefix(p, s) -> p + s' = s && t + r' = r && ra(s', p, t, r') - // else -> s = [s0] + s' && r = [s0] + r' && ra(s', p, t, r') // // Then assert // ra(s, p, t, replace_all(s, p, t)) @@ -1085,16 +1081,23 @@ namespace seq { sort* domain[4] = { srt, srt, srt, srt }; auto d = plugin.ensure_def(symbol("ra"), 4, domain, m.mk_bool_sort(), true); func_decl* ra = d.get_def()->get_decl(); + sort* isrt = a.mk_int(); + var_ref vi(m.mk_var(5, isrt), m); + var_ref vj(m.mk_var(4, isrt), m); var_ref vs(m.mk_var(3, srt), m); var_ref vp(m.mk_var(2, srt), m); var_ref vt(m.mk_var(1, srt), m); var_ref vr(m.mk_var(0, srt), m); - var* vars[4] = { vs, vp, vt, vr }; - expr_ref test1(seq.str.mk_is_empty(vs), m); - expr_ref branch1(seq.str.mk_is_empty(vr), m); - expr_ref test2(seq.str.mk_is_empty(vp), m); + var* vars[6] = { vi, vj, vs, vp, vt, vr }; + expr_ref len_s(seq.str.mk_length(vs), m); + expr_ref len_r(seq.str.mk_length(vr), m); + expr_ref test1(m.mk_eq(len_s, vi), m); + expr_ref branch1(m.mk_eq(len_r, vj), m); + expr_ref test2(m.mk_and(a.mk_gt(len_s, vi), m.mk_eq(vi, a.mk_int(0)), seq.str.mk_is_empty(vp)), m); expr_ref branch2(m.mk_eq(vr, seq.str.mk_concat(vt, vs)), m); - expr_ref test3(seq.str.mk_prefix(vp, vs), m); + NOT_IMPLEMENTED_YET(); +#if 0 + expr_ref test3(, m); expr_ref s1(m_sk.mk_prefix_inv(vp, vs), m); expr_ref r1(m_sk.mk_prefix_inv(vp, vr), m); expr* args1[4] = { s1, vp, vt, r1 }; @@ -1116,6 +1119,7 @@ namespace seq { expr* args3[4] = { s, p, t, r }; expr_ref lit(m.mk_app(ra, 4, args3), m); add_clause(lit); +#endif } void axioms::replace_re_all_axiom(expr* e) { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 286038dea..0e72de37f 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3009,7 +3009,7 @@ namespace sat { svector logits(vars.size(), 0.0); double itau = m_config.m_reorder_itau; double lse = 0; - double mid = m_rand.max_value()/2; + double mid = (double)(m_rand.max_value()/2); double max = 0; for (double& f : logits) { f = itau * (m_rand() - mid)/mid; diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index dc7f73c93..3721963c8 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -21,7 +21,6 @@ z3_add_component(sat_smt euf_invariant.cpp euf_model.cpp euf_proof.cpp - euf_relevancy.cpp euf_solver.cpp fpa_solver.cpp pb_card.cpp @@ -38,7 +37,6 @@ z3_add_component(sat_smt q_queue.cpp q_solver.cpp recfun_solver.cpp - sat_dual_solver.cpp sat_th.cpp smt_relevant.cpp user_solver.cpp diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 68f2295a2..d42a5a353 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -183,8 +183,6 @@ namespace euf { m_egraph.set_bool_var(n, v); if (m.is_eq(e) || m.is_or(e) || m.is_and(e) || m.is_not(e)) m_egraph.set_merge_enabled(n, false); - if (!si.is_bool_op(e)) - track_relevancy(lit.var()); if (s().value(lit) != l_undef) m_egraph.set_value(n, s().value(lit)); return lit; @@ -396,7 +394,7 @@ namespace euf { // Remark: The inconsistency is not going to be detected if they are // not marked as shared. - for (auto p : euf::enode_th_vars(n)) + for (auto const& p : euf::enode_th_vars(n)) if (fid2solver(p.get_id())->is_shared(p.get_var())) return true; diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp deleted file mode 100644 index 07960c584..000000000 --- a/src/sat/smt/euf_relevancy.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/*++ -Copyright (c) 2020 Microsoft Corporation - -Module Name: - - euf_relevancy.cpp - -Abstract: - - Features for relevancy tracking. - A reduced (minimal) implicant is extracted by running a dual solver. - Then the literals in the implicant are used as a basis for marking - subterms relevant. - -Author: - - Nikolaj Bjorner (nbjorner) 2020-09-22 - ---*/ - -#include "sat/smt/euf_solver.h" - -namespace euf { - - void solver::mark_relevant(sat::literal lit) { - if (m_relevancy.enabled()) { - m_relevancy.mark_relevant(lit); - return; - } - if (!relevancy_enabled()) - return; - for (; m_auto_relevant_scopes > 0; --m_auto_relevant_scopes) - m_auto_relevant_lim.push_back(m_auto_relevant.size()); - expr* e = bool_var2expr(lit.var()); - m_auto_relevant.push_back(e); - } - - void solver::pop_relevant(unsigned n) { - if (m_relevancy.enabled()) { - m_relevancy.pop(n); - return; - } - if (m_auto_relevant_scopes >= n) { - m_auto_relevant_scopes -= n; - return; - } - n -= m_auto_relevant_scopes; - m_auto_relevant_scopes = 0; - unsigned top = m_auto_relevant_lim.size() - n; - unsigned lim = m_auto_relevant_lim[top]; - m_auto_relevant_lim.shrink(top); - m_auto_relevant.shrink(lim); - } - - void solver::push_relevant() { - if (m_relevancy.enabled()) { - m_relevancy.push(); - return; - } - ++m_auto_relevant_scopes; - } - - bool solver::is_relevant(enode* n) const { - if (m_relevancy.enabled()) - return m_relevancy.is_relevant(n); - return m_relevant_expr_ids.get(n->get_expr_id(), true); - } - - bool solver::is_relevant(bool_var v) const { - if (m_relevancy.enabled()) - return m_relevancy.is_relevant(v); - auto* e = bool_var2enode(v); - return !e || is_relevant(e); - } - - void solver::ensure_dual_solver() { - if (m_relevancy.enabled()) - return; - if (m_dual_solver) - return; - m_dual_solver = alloc(sat::dual_solver, s(), s().rlimit()); - for (unsigned i = s().num_user_scopes(); i-- > 0; ) - m_dual_solver->push(); - } - - /** - * Add a root clause. Root clauses must all be satisfied by the - * final assignment. If a clause is added above search level it - * is subject to removal on backtracking. These clauses are therefore - * not tracked. - */ - void solver::add_root(unsigned n, sat::literal const* lits) { - if (m_relevancy.enabled()) { - m_relevancy.add_root(n, lits); - return; - } - if (!relevancy_enabled()) - return; - ensure_dual_solver(); - m_dual_solver->add_root(n, lits); - } - - void solver::add_aux(unsigned n, sat::literal const* lits) { - if (m_relevancy.enabled()) { - m_relevancy.add_def(n, lits); - return; - } - if (!relevancy_enabled()) - return; - ensure_dual_solver(); - m_dual_solver->add_aux(n, lits); - } - - void solver::track_relevancy(sat::bool_var v) { - if (m_relevancy.enabled()) - return; - ensure_dual_solver(); - m_dual_solver->track_relevancy(v); - } - - bool solver::init_relevancy() { - if (m_relevancy.enabled()) - return true; - m_relevant_expr_ids.reset(); - if (!relevancy_enabled()) - return true; - if (!m_dual_solver) - return true; - if (!(*m_dual_solver)()) - return false; - init_relevant_expr_ids(); - - for (auto lit : m_dual_solver->core()) - push_relevant(lit.var()); - - relevant_subterms(); - - return true; - } - - void solver::push_relevant(sat::bool_var v) { - SASSERT(!m_relevancy.enabled()); - expr* e = m_bool_var2expr.get(v, nullptr); - if (e) - m_relevant_todo.push_back(e); - } - - bool solver::is_propagated(sat::literal lit) { - SASSERT(!m_relevancy.enabled()); - return s().value(lit) == l_true && !s().get_justification(lit.var()).is_none(); - } - - void solver::init_relevant_expr_ids() { - SASSERT(!m_relevancy.enabled()); - unsigned max_id = 0; - for (enode* n : m_egraph.nodes()) - max_id = std::max(max_id, n->get_expr_id()); - m_relevant_expr_ids.resize(max_id + 1, false); - m_relevant_todo.reset(); - m_relevant_todo.append(m_auto_relevant); - } - - void solver::relevant_subterms() { - SASSERT(!m_relevancy.enabled()); - ptr_vector& todo = m_relevant_todo; - bool_vector& visited = m_relevant_visited; - for (unsigned i = 0; i < todo.size(); ++i) { - expr* e = todo[i]; - if (visited.get(e->get_id(), false)) - continue; - visited.setx(e->get_id(), true, false); - if (si.is_bool_op(e)) - continue; - else - m_relevant_expr_ids.setx(e->get_id(), true, false); - if (!is_app(e)) - continue; - expr* c = nullptr, *th = nullptr, *el = nullptr; - if (m.is_ite(e, c, th, el) && get_enode(c)) { - sat::literal lit = expr2literal(c); - todo.push_back(c); - switch (s().value(lit)) { - case l_true: - todo.push_back(th); - break; - case l_false: - todo.push_back(el); - break; - default: - todo.push_back(th); - todo.push_back(el); - break; - } - continue; - } - for (expr* arg : *to_app(e)) - todo.push_back(arg); - } - - for (auto * e : todo) - visited[e->get_id()] = false; - - TRACE("euf", - for (enode* n : m_egraph.nodes()) - if (is_relevant(n)) - tout << "relevant " << n->get_expr_id() << " [r" << n->get_root_id() << "]: " << mk_bounded_pp(n->get_expr(), m) << "\n";); - } -} diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index f6d6e73dd..79b86e9a9 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -479,9 +479,6 @@ namespace euf { if (unit_propagate()) return sat::check_result::CR_CONTINUE; - - if (!init_relevancy()) - give_up = true; unsigned num_nodes = m_egraph.num_nodes(); auto apply_solver = [&](th_solver* e) { @@ -546,9 +543,7 @@ namespace euf { for (auto* e : m_solvers) e->push(); m_egraph.push(); - if (m_dual_solver) - m_dual_solver->push(); - push_relevant(); + m_relevancy.push(); } void solver::pop(unsigned n) { @@ -558,7 +553,7 @@ namespace euf { e->pop(n); si.pop(n); m_egraph.pop(n); - pop_relevant(n); + m_relevancy.pop(n); scope const & sc = m_scopes[m_scopes.size() - n]; for (unsigned i = m_var_trail.size(); i-- > sc.m_var_lim; ) { bool_var v = m_var_trail[i]; @@ -567,8 +562,6 @@ namespace euf { } m_var_trail.shrink(sc.m_var_lim); m_scopes.shrink(m_scopes.size() - n); - if (m_dual_solver) - m_dual_solver->pop(n); SASSERT(m_egraph.num_scopes() == m_scopes.size()); TRACE("euf_verbose", display(tout << "pop to: " << m_scopes.size() << "\n");); } @@ -741,6 +734,13 @@ namespace euf { } } + bool solver::is_relevant(bool_var v) const { + if (m_relevancy.enabled()) + return m_relevancy.is_relevant(v); + auto* e = bool_var2enode(v); + return !e || is_relevant(e); + } + void solver::relevant_eh(euf::enode* n) { if (m_qsolver) m_qsolver->relevant_eh(n); diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 12afc492f..77fce4a20 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -25,7 +25,6 @@ Author: #include "sat/sat_extension.h" #include "sat/smt/atom2bool_var.h" #include "sat/smt/sat_th.h" -#include "sat/smt/sat_dual_solver.h" #include "sat/smt/euf_ackerman.h" #include "sat/smt/user_solver.h" #include "sat/smt/smt_relevant.h" @@ -184,14 +183,11 @@ namespace euf { void init_drat(); // relevancy - bool_vector m_relevant_expr_ids; - bool_vector m_relevant_visited; - ptr_vector m_relevant_todo; - void ensure_dual_solver(); - bool init_relevancy(); - void relevant_subterms(); - void init_relevant_expr_ids(); - void push_relevant(sat::bool_var v); + //bool_vector m_relevant_expr_ids; + //bool_vector m_relevant_visited; + //ptr_vector m_relevant_todo; + //void init_relevant_expr_ids(); + //void push_relevant(sat::bool_var v); bool is_propagated(sat::literal lit); // invariant void check_eqc_bool_assignment() const; @@ -376,29 +372,26 @@ namespace euf { // relevancy bool m_relevancy_enabled = true; - scoped_ptr m_dual_solver; ptr_vector m_auto_relevant; unsigned_vector m_auto_relevant_lim; unsigned m_auto_relevant_scopes = 0; bool relevancy_enabled() const { return m_relevancy_enabled && get_config().m_relevancy_lvl > 0; } void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy_enabled = false; } - void add_root(unsigned n, sat::literal const* lits); + void add_root(unsigned n, sat::literal const* lits) { m_relevancy.add_root(n, lits); } void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } - void add_aux(unsigned n, sat::literal const* lits); + void add_aux(unsigned n, sat::literal const* lits) { m_relevancy.add_def(n, lits); } void add_aux(sat::literal a) { sat::literal lits[1] = { a }; add_aux(1, lits); } void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); } void add_aux(sat::literal a, sat::literal b, sat::literal c) { sat::literal lits[3] = { a, b, c }; add_aux(3, lits); } - void track_relevancy(sat::bool_var v); - bool is_relevant(enode* n) const; + void mark_relevant(sat::literal lit) { m_relevancy.mark_relevant(lit); } + bool is_relevant(enode* n) const { return m_relevancy.is_relevant(n); } bool is_relevant(bool_var v) const; bool is_relevant(sat::literal lit) const { return is_relevant(lit.var()); } - void mark_relevant(sat::literal lit); - void pop_relevant(unsigned n); - void push_relevant(); void relevant_eh(euf::enode* n); + smt::relevancy& relevancy() { return m_relevancy; } // model construction diff --git a/src/sat/smt/sat_dual_solver.cpp b/src/sat/smt/sat_dual_solver.cpp deleted file mode 100644 index d4b93b90c..000000000 --- a/src/sat/smt/sat_dual_solver.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/*++ -Copyright (c) 2020 Microsoft Corporation - -Module Name: - - sat_dual_solver.cpp - -Abstract: - - Solver for obtaining implicant. - -Author: - - Nikolaj Bjorner (nbjorner) 2020-08-25 - ---*/ -#include "sat/smt/sat_dual_solver.h" - -namespace sat { - - dual_solver::dual_solver(solver& s, reslimit& l): - s(s), - m_solver(m_params, l) - { - SASSERT(!m_solver.get_config().m_drat); - m_solver.set_incremental(true); - } - - void dual_solver::flush() { - while (m_num_scopes > 0) { - m_solver.user_push(); - m_roots.push_scope(); - m_tracked_vars.push_scope(); - m_units.push_scope(); - m_vars.push_scope(); - --m_num_scopes; - } - } - - void dual_solver::push() { - ++m_num_scopes; - } - - void dual_solver::pop(unsigned num_scopes) { - if (m_num_scopes >= num_scopes) { - m_num_scopes -= num_scopes; - return; - } - num_scopes -= m_num_scopes; - m_num_scopes = 0; - m_solver.user_pop(num_scopes); - unsigned old_sz = m_tracked_vars.old_size(num_scopes); - for (unsigned i = m_tracked_vars.size(); i-- > old_sz; ) - m_is_tracked[m_tracked_vars[i]] = false; - old_sz = m_vars.old_size(num_scopes); - for (unsigned i = m_vars.size(); i-- > old_sz; ) { - unsigned v = m_vars[i]; - unsigned w = m_ext2var[v]; - m_ext2var[v] = null_bool_var; - m_var2ext[w] = null_bool_var; - } - m_vars.pop_scope(num_scopes); - m_units.pop_scope(num_scopes); - m_roots.pop_scope(num_scopes); - m_tracked_vars.pop_scope(num_scopes); - } - - bool_var dual_solver::ext2var(bool_var v) { - bool_var w = m_ext2var.get(v, null_bool_var); - if (null_bool_var == w) { - w = m_solver.mk_var(); - m_solver.set_external(w); - s.set_external(v); - m_ext2var.setx(v, w, null_bool_var); - m_var2ext.setx(w, v, null_bool_var); - m_vars.push_back(v); - } - return w; - } - - void dual_solver::track_relevancy(bool_var w) { - flush(); - bool_var v = ext2var(w); - if (!m_is_tracked.get(v, false)) { - m_is_tracked.setx(v, true, false); - m_tracked_vars.push_back(v); - } - } - - literal dual_solver::ext2lit(literal lit) { - return literal(ext2var(lit.var()), lit.sign()); - } - - literal dual_solver::lit2ext(literal lit) { - return literal(m_var2ext[lit.var()], lit.sign()); - } - - void dual_solver::add_root(unsigned sz, literal const* clause) { - flush(); - if (false && sz == 1) { - TRACE("dual", tout << "unit: " << clause[0] << "\n";); - m_units.push_back(clause[0]); - return; - } - literal root; - if (sz == 1) - root = ext2lit(clause[0]); - else { - root = literal(m_solver.mk_var(), false); - for (unsigned i = 0; i < sz; ++i) - m_solver.mk_clause(root, ~ext2lit(clause[i]), status::input()); - } - m_solver.set_external(root.var()); - m_roots.push_back(~root); - TRACE("dual", tout << "root: " << ~root << " => " << literal_vector(sz, clause) << "\n";); - } - - void dual_solver::add_aux(unsigned sz, literal const* clause) { - flush(); - m_lits.reset(); - for (unsigned i = 0; i < sz; ++i) - m_lits.push_back(ext2lit(clause[i])); - TRACE("dual", tout << "aux: " << literal_vector(sz, clause) << " -> " << m_lits << "\n";); - m_solver.mk_clause(sz, m_lits.data(), status::input()); - } - - void dual_solver::add_assumptions() { - flush(); - m_lits.reset(); - for (bool_var v : m_tracked_vars) - m_lits.push_back(literal(v, l_false == s.value(m_var2ext[v]))); - for (auto lit : m_units) { - bool_var w = m_ext2var.get(lit.var(), null_bool_var); - if (w != null_bool_var) - m_lits.push_back(ext2lit(lit)); - } - } - - bool dual_solver::operator()() { - m_core.reset(); - m_core.append(m_units); - if (m_roots.empty()) - return true; - m_solver.user_push(); - m_solver.add_clause(m_roots.size(), m_roots.data(), status::input()); - add_assumptions(); - lbool is_sat = m_solver.check(m_lits.size(), m_lits.data()); - if (is_sat == l_false) - for (literal lit : m_solver.get_core()) - m_core.push_back(lit2ext(lit)); - if (is_sat == l_true) { - TRACE("dual", display(tout); s.display(tout);); - IF_VERBOSE(0, verbose_stream() << "unexpected SAT\n"); - IF_VERBOSE(0, verbose_stream() << "assumptions: " << m_lits << "\n"); - IF_VERBOSE(0, display(verbose_stream()); s.display(verbose_stream());); - UNREACHABLE(); - return false; - } - TRACE("dual", m_solver.display(tout << "is-sat: " << is_sat << " core: " << m_core << "\n");); - m_solver.user_pop(1); - return is_sat == l_false; - } - - std::ostream& dual_solver::display(std::ostream& out) const { - for (unsigned v = 0; v < m_solver.num_vars(); ++v) { - bool_var w = m_var2ext.get(v, null_bool_var); - if (w == null_bool_var) - continue; - lbool v1 = m_solver.value(v); - lbool v2 = s.value(w); - if (v1 == v2 || v2 == l_undef) - continue; - out << "ext: " << w << " " << v2 << "\n"; - out << "int: " << v << " " << v1 << "\n"; - } - literal_vector lits; - for (bool_var v : m_tracked_vars) - lits.push_back(literal(m_var2ext[v], l_false == s.value(m_var2ext[v]))); - out << "tracked: " << lits << "\n"; - lits.reset(); - for (literal r : m_roots) - if (m_solver.value(r) == l_true) - lits.push_back(r); - out << "roots: " << lits << "\n"; - m_solver.display(out); - - return out; - } -} diff --git a/src/sat/smt/sat_dual_solver.h b/src/sat/smt/sat_dual_solver.h deleted file mode 100644 index d9b43f7af..000000000 --- a/src/sat/smt/sat_dual_solver.h +++ /dev/null @@ -1,84 +0,0 @@ -/*++ -Copyright (c) 2020 Microsoft Corporation - -Module Name: - - sat_dual_solver.h - -Abstract: - - Solver for obtaining implicant. - Based on an idea by Armin Biere to use dual propagation - for representation of negated goal. - -Author: - - Nikolaj Bjorner (nbjorner) 2020-08-25 - ---*/ -#pragma once -#include "util/lim_vector.h" -#include "sat/sat_solver.h" - -namespace sat { - - class dual_solver { - class dual_params : public no_drat_params { - public: - dual_params() { - set_bool("core.minimize", false); - } - }; - solver& s; - dual_params m_params; - solver m_solver; - lim_svector m_units, m_roots; - lim_svector m_tracked_vars; - literal_vector m_lits, m_core; - bool_var_vector m_is_tracked; - unsigned_vector m_ext2var; - unsigned_vector m_var2ext; - lim_svector m_vars; - unsigned m_num_scopes = 0; - void add_literal(literal lit); - - bool_var ext2var(bool_var v); - bool_var var2ext(bool_var v); - literal ext2lit(literal lit); - literal lit2ext(literal lit); - - void add_assumptions(); - - std::ostream& display(std::ostream& out) const; - - void flush(); - - public: - dual_solver(solver& s, reslimit& l); - void push(); - void pop(unsigned num_scopes); - - /* - * track model relevancy for variable - */ - void track_relevancy(bool_var v); - - /* - * Add a root clause from the input problem. - * At least one literal has to be satisfied in every root. - */ - void add_root(unsigned sz, literal const* clause); - - /* - * Add auxiliary clauses that originate from compiling definitions. - */ - void add_aux(unsigned sz, literal const* clause); - - /* - * Extract a minimized subset of relevant literals from a model for s. - */ - bool operator()(); - - literal_vector const& core() const { return m_core; } - }; -} diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/smt_relevant.cpp index a037090a2..87a85f61b 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/smt_relevant.cpp @@ -44,6 +44,8 @@ namespace smt { } void relevancy::pop(unsigned n) { + if (!m_enabled) + return; if (n <= m_num_scopes) { m_num_scopes -= n; return; @@ -55,7 +57,7 @@ namespace smt { SASSERT(n > 0); unsigned sz = m_lim[m_lim.size() - n]; for (unsigned i = m_trail.size(); i-- > sz; ) { - auto [u, idx] = m_trail[i]; + auto const& [u, idx] = m_trail[i]; switch (u) { case update::relevant_var: m_relevant_var_ids[idx] = false; @@ -168,7 +170,7 @@ namespace smt { return; m_trail.push_back(std::make_pair(update::set_qhead, m_qhead)); while (m_qhead < m_queue.size() && !ctx.s().inconsistent() && ctx.get_manager().inc()) { - auto [lit, n] = m_queue[m_qhead++]; + auto const& [lit, n] = m_queue[m_qhead++]; SASSERT(n || lit != sat::null_literal); SASSERT(!n || lit == sat::null_literal); if (n) diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/smt_relevant.h index 723cf613a..e27694ae2 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/smt_relevant.h @@ -137,7 +137,7 @@ namespace smt { public: relevancy(euf::solver& ctx); - void push() { ++m_num_scopes; } + void push() { if (m_enabled) ++m_num_scopes; } void pop(unsigned n); void add_root(unsigned n, sat::literal const* lits); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index e3386b4e2..a6d5625ee 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -186,8 +186,6 @@ struct goal2sat::imp : public sat::sat_internalizer { return v; v = m_solver.add_var(is_ext); log_def(v, n); - if (top_level_relevant() && !is_bool_op(n)) - ensure_euf()->track_relevancy(v); return v; } @@ -216,10 +214,6 @@ struct goal2sat::imp : public sat::sat_internalizer { if (!m_expr2var_replay || !m_expr2var_replay->find(t, v)) v = add_var(true, t); m_map.insert(t, v); - if (relevancy_enabled() && (m.is_true(t) || m.is_false(t))) { - add_dual_root(sat::literal(v, m.is_false(t))); - ensure_euf()->track_relevancy(v); - } return v; } @@ -678,8 +672,6 @@ struct goal2sat::imp : public sat::sat_internalizer { } if (lit == sat::null_literal) return; - if (top_level_relevant()) - euf->track_relevancy(lit.var()); if (root) mk_root_clause(lit); else diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index 892a88f89..ef9c1f4f2 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -135,6 +135,7 @@ class sat_tactic : public tactic { ref mc; m_sat2goal(*m_solver, map, m_params, *(g.get()), mc); g->add(mc.get()); + g->display(std::cout); if (produce_core || m_goal2sat.has_interpreted_funs()) { // sat2goal does not preseve assumptions or assignments to interpreted atoms g->updt_prec(goal::OVER); From a2a5924e5c3986331545ba9ab19ae1e0b4841da5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 14:14:09 -0800 Subject: [PATCH 68/88] purge more --- src/sat/smt/euf_solver.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 77fce4a20..3a48ae3b1 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -371,13 +371,9 @@ namespace euf { bool enable_ackerman_axioms(expr* n) const; // relevancy - bool m_relevancy_enabled = true; - ptr_vector m_auto_relevant; - unsigned_vector m_auto_relevant_lim; - unsigned m_auto_relevant_scopes = 0; - bool relevancy_enabled() const { return m_relevancy_enabled && get_config().m_relevancy_lvl > 0; } - void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy_enabled = false; } + bool relevancy_enabled() const { return m_relevancy.enabled(); } + void disable_relevancy(expr* e) { IF_VERBOSE(0, verbose_stream() << "disabling relevancy " << mk_pp(e, m) << "\n"); m_relevancy.set_enabled(false); } void add_root(unsigned n, sat::literal const* lits) { m_relevancy.add_root(n, lits); } void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } From a086f6218bb3d235159a7763e3d577edfa6ef651 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 14:15:41 -0800 Subject: [PATCH 69/88] na Signed-off-by: Nikolaj Bjorner --- src/sat/tactic/sat_tactic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sat/tactic/sat_tactic.cpp b/src/sat/tactic/sat_tactic.cpp index ef9c1f4f2..892a88f89 100644 --- a/src/sat/tactic/sat_tactic.cpp +++ b/src/sat/tactic/sat_tactic.cpp @@ -135,7 +135,6 @@ class sat_tactic : public tactic { ref mc; m_sat2goal(*m_solver, map, m_params, *(g.get()), mc); g->add(mc.get()); - g->display(std::cout); if (produce_core || m_goal2sat.has_interpreted_funs()) { // sat2goal does not preseve assumptions or assignments to interpreted atoms g->updt_prec(goal::OVER); From fc741cf01868e12195ff0749df982fd994be8cc2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 14:23:22 -0800 Subject: [PATCH 70/88] rename module Signed-off-by: Nikolaj Bjorner --- src/sat/smt/CMakeLists.txt | 2 +- src/sat/smt/array_internalize.cpp | 2 +- src/sat/smt/{smt_relevant.cpp => euf_relevancy.cpp} | 4 ++-- src/sat/smt/{smt_relevant.h => euf_relevancy.h} | 7 +++---- src/sat/smt/euf_solver.h | 6 +++--- src/sat/smt/q_ematch.cpp | 6 +++--- 6 files changed, 13 insertions(+), 14 deletions(-) rename src/sat/smt/{smt_relevant.cpp => euf_relevancy.cpp} (99%) rename src/sat/smt/{smt_relevant.h => euf_relevancy.h} (99%) diff --git a/src/sat/smt/CMakeLists.txt b/src/sat/smt/CMakeLists.txt index 3721963c8..a75c0022d 100644 --- a/src/sat/smt/CMakeLists.txt +++ b/src/sat/smt/CMakeLists.txt @@ -21,6 +21,7 @@ z3_add_component(sat_smt euf_invariant.cpp euf_model.cpp euf_proof.cpp + euf_relevancy.cpp euf_solver.cpp fpa_solver.cpp pb_card.cpp @@ -38,7 +39,6 @@ z3_add_component(sat_smt q_solver.cpp recfun_solver.cpp sat_th.cpp - smt_relevant.cpp user_solver.cpp COMPONENT_DEPENDENCIES sat diff --git a/src/sat/smt/array_internalize.cpp b/src/sat/smt/array_internalize.cpp index 683cc5d07..5e1a76b9f 100644 --- a/src/sat/smt/array_internalize.cpp +++ b/src/sat/smt/array_internalize.cpp @@ -86,7 +86,7 @@ namespace array { for (auto* arg : euf::enode_args(n)) ensure_var(arg); internalize_eh(n); - if (ctx.is_relevant(n) || !ctx.relevancy().enabled()) + if (ctx.is_relevant(n)) relevant_eh(n); return true; } diff --git a/src/sat/smt/smt_relevant.cpp b/src/sat/smt/euf_relevancy.cpp similarity index 99% rename from src/sat/smt/smt_relevant.cpp rename to src/sat/smt/euf_relevancy.cpp index 87a85f61b..869df879e 100644 --- a/src/sat/smt/smt_relevant.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -16,10 +16,10 @@ Author: --*/ #include "sat/sat_solver.h" #include "sat/smt/euf_solver.h" -#include "sat/smt/smt_relevant.h" +#include "sat/smt/euf_relevancy.h" -namespace smt { +namespace euf { relevancy::relevancy(euf::solver& ctx): ctx(ctx) { } diff --git a/src/sat/smt/smt_relevant.h b/src/sat/smt/euf_relevancy.h similarity index 99% rename from src/sat/smt/smt_relevant.h rename to src/sat/smt/euf_relevancy.h index e27694ae2..bcbcaf877 100644 --- a/src/sat/smt/smt_relevant.h +++ b/src/sat/smt/euf_relevancy.h @@ -97,11 +97,10 @@ Do we need full watch lists instead of 2-watch lists? #include "sat/sat_solver.h" #include "sat/smt/sat_th.h" -namespace euf { - class solver; -} -namespace smt { +namespace euf { + + class solver; class relevancy { euf::solver& ctx; diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 3a48ae3b1..1913e1bd3 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -27,7 +27,7 @@ Author: #include "sat/smt/sat_th.h" #include "sat/smt/euf_ackerman.h" #include "sat/smt/user_solver.h" -#include "sat/smt/smt_relevant.h" +#include "sat/smt/euf_relevancy.h" #include "smt/params/smt_params.h" @@ -92,7 +92,7 @@ namespace euf { std::function<::solver*(void)> m_mk_solver; ast_manager& m; sat::sat_internalizer& si; - smt::relevancy m_relevancy; + relevancy m_relevancy; smt_params m_config; euf::egraph m_egraph; trail_stack m_trail; @@ -388,7 +388,7 @@ namespace euf { bool is_relevant(sat::literal lit) const { return is_relevant(lit.var()); } void relevant_eh(euf::enode* n); - smt::relevancy& relevancy() { return m_relevancy; } + relevancy& get_relevancy() { return m_relevancy; } // model construction void update_model(model_ref& mdl); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index 8d3bc5995..1665ec74c 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -69,13 +69,13 @@ namespace q { m_mam->add_node(n, false); }; ctx.get_egraph().set_on_merge(_on_merge); - if (!ctx.relevancy().enabled()) + if (!ctx.relevancy_enabled()) ctx.get_egraph().set_on_make(_on_make); m_mam = mam::mk(ctx, *this); } void ematch::relevant_eh(euf::enode* n) { - if (ctx.relevancy().enabled()) + if (ctx.relevancy_enabled()) m_mam->add_node(n, false); } @@ -358,7 +358,7 @@ namespace q { if (m_prop_queue.empty()) return false; for (unsigned i = 0; i < m_prop_queue.size(); ++i) { - auto [is_conflict, idx, j_idx] = m_prop_queue[i]; + auto const& [is_conflict, idx, j_idx] = m_prop_queue[i]; propagate(is_conflict, idx, j_idx); } m_prop_queue.reset(); From 614c66f1e2c44509fa068a9387df370b2b4deeaf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 17:21:37 -0800 Subject: [PATCH 71/88] missing relevancy propagation --- src/sat/smt/euf_internalize.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index d42a5a353..8a7d16b31 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -304,6 +304,8 @@ namespace euf { literal lits2[2] = { lit_c, lit_el }; s().add_clause(2, lits1, st); s().add_clause(2, lits2, st); + add_root(2, lits1); + add_root(2, lits2); } } else if (m.is_distinct(e)) { @@ -322,6 +324,8 @@ namespace euf { sat::literal lits2[2] = { dist, some_eq }; s().add_clause(2, lits1, st); s().add_clause(2, lits2, st); + add_root(2, lits1); + add_root(2, lits2); } else if (m.is_eq(e, th, el) && !m.is_iff(e)) { sat::literal lit1 = expr2literal(e); @@ -334,6 +338,8 @@ namespace euf { sat::literal lits2[2] = { lit1, ~lit2 }; s().add_clause(2, lits1, st); s().add_clause(2, lits2, st); + add_root(2, lits1); + add_root(2, lits2); } } } From 4a1975053febec5a308c1610653c2427683f3c0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jan 2022 17:37:04 -0800 Subject: [PATCH 72/88] cleanup --- src/sat/sat_solver.h | 5 ++++ src/sat/sat_solver_core.h | 5 +--- src/sat/smt/euf_internalize.cpp | 45 +++++++++++++-------------------- src/sat/smt/euf_solver.h | 1 + 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index f6cc881b5..74bb182e8 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -266,6 +266,11 @@ namespace sat { // // ----------------------- void add_clause(unsigned num_lits, literal * lits, sat::status st) override { mk_clause(num_lits, lits, st); } + void add_clause(literal l1, literal l2, status st) { + literal lits[2] = { l1, l2 }; + add_clause(2, lits, st); + } + void add_clause(literal lit, status st) { literal lits[1] = { lit }; add_clause(1, lits, st); } bool_var add_var(bool ext) override { return mk_var(ext, true); } bool_var mk_var(bool ext = false, bool dvar = true); diff --git a/src/sat/sat_solver_core.h b/src/sat/sat_solver_core.h index ca66003cb..407deae5c 100644 --- a/src/sat/sat_solver_core.h +++ b/src/sat/sat_solver_core.h @@ -35,10 +35,7 @@ namespace sat { // add clauses virtual void add_clause(unsigned n, literal* lits, status st) = 0; - void add_clause(literal l1, literal l2, status st) { - literal lits[2] = {l1, l2}; - add_clause(2, lits, st); - } + void add_clause(literal l1, literal l2, literal l3, status st) { literal lits[3] = {l1, l2, l3}; add_clause(3, lits, st); diff --git a/src/sat/smt/euf_internalize.cpp b/src/sat/smt/euf_internalize.cpp index 8a7d16b31..51f342fe1 100644 --- a/src/sat/smt/euf_internalize.cpp +++ b/src/sat/smt/euf_internalize.cpp @@ -220,8 +220,8 @@ namespace euf { lits.push_back(lit); } } - s().mk_clause(lits, st); add_root(lits); + s().mk_clause(lits, st); } else { // g(f(x_i)) = x_i @@ -239,14 +239,13 @@ namespace euf { expr_ref gapp(m.mk_app(g, fapp.get()), m); expr_ref eq = mk_eq(gapp, arg); sat::literal lit = mk_literal(eq); - s().add_clause(1, &lit, st); + s().add_clause(lit, st); eqs.push_back(mk_eq(fapp, a)); } pb_util pb(m); expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.data(), 2), m); sat::literal lit = si.internalize(at_least2, m_is_redundant); - s().mk_clause(1, &lit, st); - add_root(lit); + s().add_clause(lit, st); } } @@ -262,8 +261,7 @@ namespace euf { for (unsigned j = i + 1; j < sz; ++j) { expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr()); sat::literal lit = ~mk_literal(eq); - s().add_clause(1, &lit, st); - add_root(1, &lit); + s().add_clause(lit, st); } } } @@ -280,8 +278,7 @@ namespace euf { n->mark_interpreted(); expr_ref eq = mk_eq(fapp, fresh); sat::literal lit = mk_literal(eq); - s().add_clause(1, &lit, st); - add_root(1, &lit); + s().add_clause(lit, st); } } } @@ -294,18 +291,16 @@ namespace euf { expr_ref eq_th = mk_eq(e, th); sat::literal lit_th = mk_literal(eq_th); if (th == el) { - s().add_clause(1, &lit_th, st); + s().add_clause(lit_th, st); } else { sat::literal lit_c = mk_literal(c); expr_ref eq_el = mk_eq(e, el); sat::literal lit_el = mk_literal(eq_el); - literal lits1[2] = { ~lit_c, lit_th }; - literal lits2[2] = { lit_c, lit_el }; - s().add_clause(2, lits1, st); - s().add_clause(2, lits2, st); - add_root(2, lits1); - add_root(2, lits2); + add_root(~lit_c, lit_th); + add_root(lit_c, lit_el); + s().add_clause(~lit_c, lit_th, st); + s().add_clause(lit_c, lit_el, st); } } else if (m.is_distinct(e)) { @@ -320,12 +315,10 @@ namespace euf { expr_ref fml(m.mk_or(eqs), m); sat::literal dist(si.to_bool_var(e), false); sat::literal some_eq = si.internalize(fml, m_is_redundant); - sat::literal lits1[2] = { ~dist, ~some_eq }; - sat::literal lits2[2] = { dist, some_eq }; - s().add_clause(2, lits1, st); - s().add_clause(2, lits2, st); - add_root(2, lits1); - add_root(2, lits2); + add_root(~dist, ~some_eq); + add_root(dist, some_eq); + s().add_clause(~dist, ~some_eq, st); + s().add_clause(dist, some_eq, st); } else if (m.is_eq(e, th, el) && !m.is_iff(e)) { sat::literal lit1 = expr2literal(e); @@ -334,12 +327,10 @@ namespace euf { enode* n2 = m_egraph.find(e2); if (n2) { sat::literal lit2 = expr2literal(e2); - sat::literal lits1[2] = { ~lit1, lit2 }; - sat::literal lits2[2] = { lit1, ~lit2 }; - s().add_clause(2, lits1, st); - s().add_clause(2, lits2, st); - add_root(2, lits1); - add_root(2, lits2); + add_root(~lit1, lit2); + add_root(lit1, ~lit2); + s().add_clause(~lit1, lit2, st); + s().add_clause(lit1, ~lit2, st); } } } diff --git a/src/sat/smt/euf_solver.h b/src/sat/smt/euf_solver.h index 1913e1bd3..859c0640c 100644 --- a/src/sat/smt/euf_solver.h +++ b/src/sat/smt/euf_solver.h @@ -377,6 +377,7 @@ namespace euf { void add_root(unsigned n, sat::literal const* lits) { m_relevancy.add_root(n, lits); } void add_root(sat::literal_vector const& lits) { add_root(lits.size(), lits.data()); } void add_root(sat::literal lit) { add_root(1, &lit); } + void add_root(sat::literal lit1, sat::literal lit2) { sat::literal lits[2] = { lit1, lit2, }; add_root(2, lits); } void add_aux(sat::literal_vector const& lits) { add_aux(lits.size(), lits.data()); } void add_aux(unsigned n, sat::literal const* lits) { m_relevancy.add_def(n, lits); } void add_aux(sat::literal a) { sat::literal lits[1] = { a }; add_aux(1, lits); } From d1fb83103084cfcaa80ca8f8d687809a21f5e877 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 16:03:31 -0800 Subject: [PATCH 73/88] relevancy overhaul --- src/ast/euf/euf_egraph.cpp | 11 +++- src/sat/smt/euf_model.cpp | 7 +-- src/sat/smt/euf_relevancy.cpp | 109 +++++++++++++++++++--------------- src/sat/smt/euf_relevancy.h | 22 +++++-- src/sat/smt/euf_solver.cpp | 8 +-- src/sat/tactic/goal2sat.cpp | 20 ++----- 6 files changed, 97 insertions(+), 80 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 73df52762..8a3a4e002 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -785,8 +785,15 @@ namespace euf { out << " " << p->get_expr_id(); out << "] "; } - if (n->value() != l_undef) - out << "[b" << n->bool_var() << " := " << (n->value() == l_true ? "T":"F") << (n->merge_tf()?"":" no merge") << "] "; + auto value_of = [&]() { + switch (n->value()) { + case l_true: return "T"; + case l_false: return "F"; + default: return "?"; + } + }; + if (n->bool_var() != sat::null_bool_var) + out << "[b" << n->bool_var() << " := " << value_of() << (n->merge_tf() ? "" : " no merge") << "] "; if (n->has_th_vars()) { out << "[t"; for (auto const& v : enode_th_vars(n)) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index ded947da3..c0b9d9c85 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -161,10 +161,9 @@ namespace euf { default: break; } - if (is_app(e) && to_app(e)->get_family_id() == m.get_basic_family_id()) - continue; sat::bool_var v = get_enode(e)->bool_var(); - SASSERT(v != sat::null_bool_var); + if (v == sat::null_bool_var) + continue; switch (s().value(v)) { case l_true: m_values.set(id, m.mk_true()); @@ -224,7 +223,7 @@ namespace euf { enode* earg = get_enode(arg); expr* val = m_values.get(earg->get_root_id()); args.push_back(val); - CTRACE("euf", !val, tout << "no value for " << bpp(earg) << "\n";); + CTRACE("euf", !val, tout << "no value for " << bpp(earg) << "\n" << bpp(n) << "\n"; display(tout);); SASSERT(val); } SASSERT(args.size() == arity); diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 869df879e..a24277293 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -20,28 +20,6 @@ Author: namespace euf { - - relevancy::relevancy(euf::solver& ctx): ctx(ctx) { - } - - void relevancy::relevant_eh(euf::enode* n) { - SASSERT(is_relevant(n)); - ctx.relevant_eh(n); - } - - void relevancy::relevant_eh(sat::literal lit) { - SASSERT(is_relevant(lit)); - switch (ctx.s().value(lit)) { - case l_true: - ctx.asserted(lit); - break; - case l_false: - ctx.asserted(~lit); - break; - default: - break; - } - } void relevancy::pop(unsigned n) { if (!m_enabled) @@ -61,9 +39,8 @@ namespace euf { switch (u) { case update::relevant_var: m_relevant_var_ids[idx] = false; - m_queue.pop_back(); break; - case update::relevant_node: + case update::add_queue: m_queue.pop_back(); break; case update::add_clause: { @@ -120,10 +97,11 @@ namespace euf { } } - void relevancy::add_def(unsigned n, sat::literal const* lits) { + void relevancy::add_def(unsigned n, sat::literal const* lits) { if (!m_enabled) return; flush(); + TRACE("relevancy", tout << "def " << sat::literal_vector(n, lits) << "\n"); for (unsigned i = 0; i < n; ++i) { if (ctx.s().value(lits[i]) == l_false && is_relevant(lits[i])) { add_root(n, lits); @@ -141,21 +119,42 @@ namespace euf { } } + void relevancy::add_to_propagation_queue(sat::literal lit) { + m_trail.push_back(std::make_pair(update::add_queue, lit.var())); + m_queue.push_back(std::make_pair(lit, nullptr)); + } + + void relevancy::set_relevant(sat::literal lit) { + euf::enode* n = ctx.bool_var2enode(lit.var()); + if (n) + mark_relevant(n); + m_relevant_var_ids.setx(lit.var(), true, false); + m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); + } + void relevancy::asserted(sat::literal lit) { + TRACE("relevancy", tout << "asserted " << lit << " relevant " << is_relevant(lit) << "\n"); if (!m_enabled) return; flush(); - if (ctx.s().lvl(lit) <= ctx.s().search_lvl()) { - mark_relevant(lit); + if (is_relevant(lit)) { + add_to_propagation_queue(lit); return; } + if (ctx.s().lvl(lit) <= ctx.s().search_lvl()) { + set_relevant(lit); + add_to_propagation_queue(lit); + return; + } + for (auto idx : occurs(lit)) { if (!m_roots[idx]) continue; for (sat::literal lit2 : *m_clauses[idx]) if (lit2 != lit && ctx.s().value(lit2) == l_true && is_relevant(lit2)) - goto next; - mark_relevant(lit); + goto next; + set_relevant(lit); + add_to_propagation_queue(lit); return; next: ; @@ -181,6 +180,7 @@ namespace euf { } void relevancy::merge(euf::enode* root, euf::enode* other) { + TRACE("relevancy", tout << "merge #" << ctx.bpp(root) << " " << is_relevant(root) << " #" << ctx.bpp(other) << " " << is_relevant(other) << "\n"); if (is_relevant(root)) mark_relevant(other); else if (is_relevant(other)) @@ -193,28 +193,36 @@ namespace euf { flush(); if (is_relevant(n)) return; - if (ctx.get_si().is_bool_op(n->get_expr())) - return; - m_trail.push_back(std::make_pair(update::relevant_node, 0)); + TRACE("relevancy", tout << "mark #" << ctx.bpp(n) << "\n"); + m_trail.push_back(std::make_pair(update::add_queue, 0)); m_queue.push_back(std::make_pair(sat::null_literal, n)); } void relevancy::mark_relevant(sat::literal lit) { + TRACE("relevancy", tout << "mark " << lit << " " << is_relevant(lit) << " " << ctx.s().value(lit) << " lim: " << m_lim.size() << "\n"); if (!m_enabled) return; flush(); if (is_relevant(lit)) return; - euf::enode* n = ctx.bool_var2enode(lit.var()); - if (n) - mark_relevant(n); - m_relevant_var_ids.setx(lit.var(), true, false); - m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); - m_queue.push_back(std::make_pair(lit, nullptr)); + set_relevant(lit); + switch (ctx.s().value(lit)) { + case l_true: + break; + case l_false: + lit.neg(); + break; + default: + return; + } + add_to_propagation_queue(lit); } void relevancy::propagate_relevant(sat::literal lit) { - relevant_eh(lit); + SASSERT(m_num_scopes == 0); + TRACE("relevancy", tout << "propagate " << lit << " lim: " << m_lim.size() << "\n"); + SASSERT(ctx.s().value(lit) == l_true); + SASSERT(is_relevant(lit)); euf::enode* n = ctx.bool_var2enode(lit.var()); if (n && !ctx.get_si().is_bool_op(n->get_expr())) return; @@ -231,13 +239,17 @@ namespace euf { } } - if (true_lit != sat::null_literal) - mark_relevant(true_lit); + if (true_lit != sat::null_literal) { + set_relevant(true_lit); + add_to_propagation_queue(true_lit); + ctx.asserted(true_lit); + } else { m_trail.push_back(std::make_pair(update::set_root, idx)); m_roots[idx] = true; } next: + TRACE("relevancy", tout << "propagate " << lit << " " << true_lit << " " << m_roots[idx] << "\n"); ; } } @@ -247,22 +259,25 @@ namespace euf { while (!m_todo.empty()) { n = m_todo.back(); m_todo.pop_back(); + TRACE("relevancy", tout << "propagate #" << ctx.bpp(n) << " lim: " << m_lim.size() << "\n"); if (n->is_relevant()) continue; - if (ctx.get_si().is_bool_op(n->get_expr())) - continue; m_stack.push_back(n); while (!m_stack.empty()) { n = m_stack.back(); unsigned sz = m_stack.size(); - for (euf::enode* arg : euf::enode_args(n)) - if (!arg->is_relevant()) - m_stack.push_back(arg); + bool is_bool_op = ctx.get_si().is_bool_op(n->get_expr()); + if (!is_bool_op) + for (euf::enode* arg : euf::enode_args(n)) + if (!arg->is_relevant()) + m_stack.push_back(arg); if (sz != m_stack.size()) continue; if (!n->is_relevant()) { ctx.get_egraph().set_relevant(n); - relevant_eh(n); + ctx.relevant_eh(n); + if (n->bool_var() != sat::null_bool_var) + mark_relevant(sat::literal(n->bool_var())); for (euf::enode* sib : euf::enode_class(n)) if (!sib->is_relevant()) m_todo.push_back(sib); diff --git a/src/sat/smt/euf_relevancy.h b/src/sat/smt/euf_relevancy.h index bcbcaf877..b64b1d7f8 100644 --- a/src/sat/smt/euf_relevancy.h +++ b/src/sat/smt/euf_relevancy.h @@ -91,6 +91,16 @@ Do we need full watch lists instead of 2-watch lists? roots. + State machine for literals: relevant(lit), assigned(lit) + +relevant(lit) transitions false -> true + if assigned(lit): add to propagation queue + if not assigned(lit): no-op (or mark enodes as relevant) + +assigned(lit) transitions false -> true + if relevant(lit): add to propagation queue + if not relevant(lit): set relevant if member of root, add to propagation queue + --*/ #pragma once @@ -105,7 +115,7 @@ namespace euf { class relevancy { euf::solver& ctx; - enum class update { relevant_var, relevant_node, add_clause, set_root, set_qhead }; + enum class update { relevant_var, add_queue, add_clause, set_root, set_qhead }; bool m_enabled = false; svector> m_trail; @@ -120,10 +130,6 @@ namespace euf { svector> m_queue; // propagation queue for relevancy euf::enode_vector m_stack, m_todo; - // callbacks during propagation - void relevant_eh(euf::enode* n); - void relevant_eh(sat::literal lit); - void push_core() { m_lim.push_back(m_trail.size()); } void flush() { for (; m_num_scopes > 0; --m_num_scopes) push_core(); } @@ -131,10 +137,14 @@ namespace euf { void propagate_relevant(sat::literal lit); + void add_to_propagation_queue(sat::literal lit); + void propagate_relevant(euf::enode* n); + void set_relevant(sat::literal lit); + public: - relevancy(euf::solver& ctx); + relevancy(euf::solver& ctx): ctx(ctx) {} void push() { if (m_enabled) ++m_num_scopes; } void pop(unsigned n); diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 79b86e9a9..7c8a42bf1 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -297,11 +297,9 @@ namespace euf { void solver::asserted(literal l) { - if (m_relevancy.enabled() && !m_relevancy.is_relevant(l)) { - m_relevancy.asserted(l); - if (!m_relevancy.is_relevant(l)) - return; - } + m_relevancy.asserted(l); + if (!m_relevancy.is_relevant(l)) + return; expr* e = m_bool_var2expr.get(l.var(), nullptr); TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << " := " << mk_bounded_pp(e, m) << "\n";); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index a6d5625ee..30d73a21a 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -125,20 +125,6 @@ struct goal2sat::imp : public sat::sat_internalizer { bool top_level_relevant() { return m_top_level && relevancy_enabled(); } - - void add_dual_def(unsigned n, sat::literal const* lits) { - if (relevancy_enabled()) - ensure_euf()->add_aux(n, lits); - } - - void add_dual_root(unsigned n, sat::literal const* lits) { - if (relevancy_enabled()) - ensure_euf()->add_root(n, lits); - } - - void add_dual_root(sat::literal lit) { - add_dual_root(1, &lit); - } void mk_clause(sat::literal l) { mk_clause(1, &l); @@ -156,7 +142,8 @@ struct goal2sat::imp : public sat::sat_internalizer { void mk_clause(unsigned n, sat::literal * lits) { TRACE("goal2sat", tout << "mk_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); - add_dual_def(n, lits); + if (relevancy_enabled()) + ensure_euf()->add_aux(n, lits); m_solver.add_clause(n, lits, mk_status()); } @@ -176,7 +163,8 @@ struct goal2sat::imp : public sat::sat_internalizer { void mk_root_clause(unsigned n, sat::literal * lits) { TRACE("goal2sat", tout << "mk_root_clause: "; for (unsigned i = 0; i < n; i++) tout << lits[i] << " "; tout << "\n";); - add_dual_root(n, lits); + if (relevancy_enabled()) + ensure_euf()->add_root(n, lits); m_solver.add_clause(n, lits, m_is_redundant ? mk_status() : sat::status::input()); } From ef3dd32364da96a52e1d61ab9415dd366344ec60 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 20:21:53 -0800 Subject: [PATCH 74/88] some cleanup Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 26 ++------------- scripts/update_api.py | 76 +++++-------------------------------------- 2 files changed, 11 insertions(+), 91 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index b73e1b329..042e6af46 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -92,7 +92,6 @@ DOTNET_CORE_ENABLED=False DOTNET_KEY_FILE=getenv("Z3_DOTNET_KEY_FILE", None) JAVA_ENABLED=False ML_ENABLED=False -JS_ENABLED=False PYTHON_INSTALL_ENABLED=False STATIC_LIB=False STATIC_BIN=False @@ -681,7 +680,7 @@ def display_help(exit_code): # Parse configuration option for mk_make script def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM - global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, JS_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED + global DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, STATIC_BIN, PREFIX, GMP, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH, GIT_DESCRIBE, PYTHON_INSTALL_ENABLED, PYTHON_ENABLED global LINUX_X64, SLOW_OPTIMIZE, LOG_SYNC, SINGLE_THREADED global GUARD_CF, ALWAYS_DYNAMIC_BASE try: @@ -749,8 +748,6 @@ def parse_options(): GIT_DESCRIBE = True elif opt in ('', '--ml'): ML_ENABLED = True - elif opt == "--js": - JS_ENABLED = True elif opt in ('', '--log-sync'): LOG_SYNC = True elif opt == '--single-threaded': @@ -813,16 +810,6 @@ def set_build_dir(d): BUILD_DIR = norm_path(d) REV_BUILD_DIR = reverse_path(d) -def set_z3js_dir(p): - global SRC_DIR, Z3JS_SRC_DIR - p = norm_path(p) - full = os.path.join(SRC_DIR, p) - if not os.path.exists(full): - raise MKException("Python bindings directory '%s' does not exist" % full) - Z3JS_SRC_DIR = full - if VERBOSE: - print("Js bindings directory was detected.") - def set_z3py_dir(p): global SRC_DIR, Z3PY_SRC_DIR p = norm_path(p) @@ -858,9 +845,6 @@ def get_components(): def get_z3py_dir(): return Z3PY_SRC_DIR -# Return directory where the js bindings are located -def get_z3js_dir(): - return Z3JS_SRC_DIR # Return true if in verbose mode def is_verbose(): @@ -872,9 +856,6 @@ def is_java_enabled(): def is_ml_enabled(): return ML_ENABLED -def is_js_enabled(): - return JS_ENABLED - def is_dotnet_core_enabled(): return DOTNET_CORE_ENABLED @@ -3025,17 +3006,14 @@ def mk_bindings(api_files): ml_output_dir = None if is_ml_enabled(): ml_output_dir = get_component('ml').src_dir - if is_js_enabled(): - set_z3js_dir("api/js") - js_output_dir = get_component('js').src_dir # Get the update_api module to do the work for us + update_api.VERBOSE = is_verbose() update_api.generate_files(api_files=new_api_files, api_output_dir=get_component('api').src_dir, z3py_output_dir=get_z3py_dir(), dotnet_output_dir=dotnet_output_dir, java_output_dir=java_output_dir, java_package_name=java_package_name, - js_output_dir=get_z3js_dir(), ml_output_dir=ml_output_dir, ml_src_dir=ml_output_dir ) diff --git a/scripts/update_api.py b/scripts/update_api.py index 6392e439e..c4e4d78f0 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -15,7 +15,6 @@ several API header files. It can also optionally emit some of the files required for Z3's different language bindings. """ -import mk_util import mk_exception import argparse import logging @@ -23,6 +22,10 @@ import re import os import sys +VERBOSE = True +def is_verbose(): + return VERBOSE + ########################################################## # TODO: rewrite this file without using global variables. # This file is a big HACK. @@ -776,62 +779,9 @@ def mk_java(java_dir, package_name): java_wrapper.write('#ifdef __cplusplus\n') java_wrapper.write('}\n') java_wrapper.write('#endif\n') - if mk_util.is_verbose(): + if is_verbose(): print("Generated '%s'" % java_nativef) - -Type2Napi = { VOID : '', VOID_PTR : '', INT : 'number', UINT : 'number', INT64 : 'number', UINT64 : 'number', DOUBLE : 'number', - FLOAT : 'number', STRING : 'string', STRING_PTR : 'array', - BOOL : 'number', SYMBOL : 'external', PRINT_MODE : 'number', ERROR_CODE : 'number', CHAR : 'number' } - -def type2napi(t): - try: - return Type2Napi[t] - except: - return "external" - -Type2NapiBuilder = { VOID : '', VOID_PTR : '', INT : 'int32', UINT : 'uint32', INT64 : 'int64', UINT64 : 'uint64', DOUBLE : 'double', - FLOAT : 'float', STRING : 'string', STRING_PTR : 'array', - BOOL : 'bool', SYMBOL : 'external', PRINT_MODE : 'int32', ERROR_CODE : 'int32', CHAR : 'char' } - -def type2napibuilder(t): - try: - return Type2NapiBuilder[t] - except: - return "external" - - -def mk_js(js_output_dir): - with open(os.path.join(js_output_dir, "z3.json"), 'w') as ous: - ous.write("{\n") - ous.write(" \"api\": [\n") - for name, result, params in _dotnet_decls: - ous.write(" {\n") - ous.write(" \"name\": \"%s\",\n" % name) - ous.write(" \"c_type\": \"%s\",\n" % Type2Str[result]) - ous.write(" \"napi_type\": \"%s\",\n" % type2napi(result)) - ous.write(" \"arg_list\": [") - first = True - for p in params: - if first: - first = False - ous.write("\n {\n") - else: - ous.write(",\n {\n") - t = param_type(p) - k = t - ous.write(" \"name\": \"%s\",\n" % "") # TBD - ous.write(" \"c_type\": \"%s\",\n" % type2str(t)) - ous.write(" \"napi_type\": \"%s\",\n" % type2napi(t)) - ous.write(" \"napi_builder\": \"%s\"\n" % type2napibuilder(t)) - ous.write( " }") - ous.write("],\n") - ous.write(" \"napi_builder\": \"%s\"\n" % type2napibuilder(result)) - ous.write(" },\n") - ous.write(" ]\n") - ous.write("}\n") - - def mk_log_header(file, name, params): file.write("void log_%s(" % name) i = 0 @@ -1364,7 +1314,7 @@ def mk_ml(ml_src_dir, ml_output_dir): ml_native.write('(**/**)\n') ml_native.close() - if mk_util.is_verbose(): + if is_verbose(): print ('Generated "%s"' % ml_nativef) mk_z3native_stubs_c(ml_src_dir, ml_output_dir) @@ -1689,7 +1639,7 @@ def mk_z3native_stubs_c(ml_src_dir, ml_output_dir): # C interface ml_wrapper.write('}\n') ml_wrapper.write('#endif\n') - if mk_util.is_verbose(): + if is_verbose(): print ('Generated "%s"' % ml_wrapperf) # Collect API(...) commands from @@ -1889,7 +1839,6 @@ def generate_files(api_files, dotnet_output_dir=None, java_output_dir=None, java_package_name=None, - js_output_dir=None, ml_output_dir=None, ml_src_dir=None): """ @@ -1950,7 +1899,7 @@ def generate_files(api_files, mk_py_wrappers() write_core_py_post(core_py) - if mk_util.is_verbose(): + if is_verbose(): print("Generated '{}'".format(log_h.name)) print("Generated '{}'".format(log_c.name)) print("Generated '{}'".format(exe_c.name)) @@ -1960,7 +1909,7 @@ def generate_files(api_files, with open(os.path.join(dotnet_output_dir, 'Native.cs'), 'w') as dotnet_file: mk_dotnet(dotnet_file) mk_dotnet_wrappers(dotnet_file) - if mk_util.is_verbose(): + if is_verbose(): print("Generated '{}'".format(dotnet_file.name)) if java_output_dir: @@ -1970,8 +1919,6 @@ def generate_files(api_files, assert not ml_src_dir is None mk_ml(ml_src_dir, ml_output_dir) - if js_output_dir: - mk_js(js_output_dir) def main(args): logging.basicConfig(level=logging.INFO) @@ -2006,10 +1953,6 @@ def main(args): dest="ml_output_dir", default=None, help="Directory to emit OCaml files. If not specified no files are emitted.") - parser.add_argument("--js_output_dir", - dest="js_output_dir", - default=None, - help="Directory to emit js bindings. If not specified no files are emitted.") pargs = parser.parse_args(args) if pargs.java_output_dir: @@ -2033,7 +1976,6 @@ def main(args): dotnet_output_dir=pargs.dotnet_output_dir, java_output_dir=pargs.java_output_dir, java_package_name=pargs.java_package_name, - js_output_dir=pargs.js_output_dir, ml_output_dir=pargs.ml_output_dir, ml_src_dir=pargs.ml_src_dir) return 0 From e943bee625a71d41b7a991a6bc6d34bed4535853 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 20:25:14 -0800 Subject: [PATCH 75/88] apply delcypher's todo Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/CMakeLists.txt | 2 -- src/sat/smt/euf_model.cpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index 98d4b9503..bab8ac982 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -18,8 +18,6 @@ add_custom_command(OUTPUT "${Z3_DOTNET_NATIVE_FILE}" ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} "${PROJECT_SOURCE_DIR}/scripts/update_api.py" ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} - # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency - "${PROJECT_SOURCE_DIR}/scripts/mk_util.py" COMMENT "Generating ${Z3_DOTNET_NATIVE_FILE}" ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} ) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index c0b9d9c85..3d0369287 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -35,7 +35,7 @@ namespace euf { s(s), m(s.m), mdl(mdl), values(values), factory(m) {} ~user_sort() { - for (auto kv : sort2values) + for (auto const& kv : sort2values) mdl->register_usort(kv.m_key, kv.m_value->size(), kv.m_value->data()); } @@ -258,7 +258,7 @@ namespace euf { if (n->is_root() && m_values.get(n->get_expr_id())) m_values2root.insert(m_values.get(n->get_expr_id()), n); TRACE("model", - for (auto kv : m_values2root) + for (auto const& kv : m_values2root) tout << mk_bounded_pp(kv.m_key, m) << "\n -> " << bpp(kv.m_value) << "\n";); return m_values2root; From 964a5cd7612ac7aad555c71003fda2d924678761 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 20:48:05 -0800 Subject: [PATCH 76/88] lump java together Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 176 ++++++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 77 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index c4e4d78f0..aa44c19e2 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -15,6 +15,7 @@ several API header files. It can also optionally emit some of the files required for Z3's different language bindings. """ + import mk_exception import argparse import logging @@ -81,42 +82,39 @@ Type2Dotnet = { VOID : 'void', VOID_PTR : 'IntPtr', INT : 'int', UINT : 'uint', FLOAT : 'float', STRING : 'string', STRING_PTR : 'byte**', BOOL : 'byte', SYMBOL : 'IntPtr', PRINT_MODE : 'uint', ERROR_CODE : 'uint', CHAR : 'char', CHAR_PTR : 'IntPtr' } -# Mapping to Java types -Type2Java = { VOID : 'void', VOID_PTR : 'long', INT : 'int', UINT : 'int', INT64 : 'long', UINT64 : 'long', DOUBLE : 'double', - FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr', - BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'long' } - -Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', INT64 : 'jlong', UINT64 : 'jlong', DOUBLE : 'jdouble', - FLOAT : 'jfloat', STRING : 'jstring', STRING_PTR : 'jobject', - BOOL : 'jboolean', SYMBOL : 'jlong', PRINT_MODE : 'jint', ERROR_CODE : 'jint', CHAR : 'jchar', CHAR_PTR : 'jlong'} # Mapping to ML types Type2ML = { VOID : 'unit', VOID_PTR : 'VOIDP', INT : 'int', UINT : 'int', INT64 : 'int', UINT64 : 'int', DOUBLE : 'float', FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string' } -next_type_id = FIRST_OBJ_ID +class DefTypes: + def __init__(self): + self.next_type_id = FIRST_OBJ_ID -def def_Type(var, c_type, py_type): - global next_type_id - exec('%s = %s' % (var, next_type_id), globals()) - Type2Str[next_type_id] = c_type - Type2PyStr[next_type_id] = py_type - next_type_id = next_type_id + 1 - -def def_Types(api_files): - pat1 = re.compile(" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*") - for api_file in api_files: - api = open(api_file, 'r') - for line in api: - m = pat1.match(line) - if m: - def_Type(m.group(1), m.group(2), m.group(3)) - for k in Type2Str: - v = Type2Str[k] - if is_obj(k): - Type2Dotnet[k] = v - Type2ML[k] = v.lower() + def def_Type(self, var, c_type, py_type): + id = self.next_type_id + exec('%s = %s' % (var, id), globals()) + Type2Str[id] = c_type + Type2PyStr[id] = py_type + self.next_type_id += 1 + + def def_Types(self, api_files): + pat1 = re.compile(" *def_Type\(\'(.*)\',[^\']*\'(.*)\',[^\']*\'(.*)\'\)[ \t]*") + for api_file in api_files: + with open(api_file, 'r') as api: + for line in api: + m = pat1.match(line) + if m: + self.def_Type(m.group(1), m.group(2), m.group(3)) + # + # Populate object type entries in dotnet and ML bindings. + # + for k in Type2Str: + v = Type2Str[k] + if is_obj(k): + Type2Dotnet[k] = v + Type2ML[k] = v.lower() def type2str(ty): global Type2Str @@ -130,19 +128,7 @@ def type2dotnet(ty): global Type2Dotnet return Type2Dotnet[ty] -def type2java(ty): - global Type2Java - if (ty >= FIRST_OBJ_ID): - return 'long' - else: - return Type2Java[ty] -def type2javaw(ty): - global Type2JavaW - if (ty >= FIRST_OBJ_ID): - return 'jlong' - else: - return Type2JavaW[ty] def type2ml(ty): global Type2ML @@ -217,42 +203,8 @@ def param2dotnet(p): else: return type2dotnet(param_type(p)) -def param2java(p): - k = param_kind(p) - if k == OUT: - if param_type(p) == INT or param_type(p) == UINT: - return "IntPtr" - elif param_type(p) == INT64 or param_type(p) == UINT64 or param_type(p) == VOID_PTR or param_type(p) >= FIRST_OBJ_ID: - return "LongPtr" - elif param_type(p) == STRING: - return "StringPtr" - else: - print("ERROR: unreachable code") - assert(False) - exit(1) - elif k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY: - return "%s[]" % type2java(param_type(p)) - elif k == OUT_MANAGED_ARRAY: - if param_type(p) == UINT: - return "UIntArrayPtr" - else: - return "ObjArrayPtr" - else: - return type2java(param_type(p)) -def param2javaw(p): - k = param_kind(p) - if k == OUT: - return "jobject" - elif k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY: - if param_type(p) == INT or param_type(p) == UINT or param_type(p) == BOOL: - return "jintArray" - else: - return "jlongArray" - elif k == OUT_MANAGED_ARRAY: - return "jlong" - else: - return type2javaw(param_type(p)) +# -------------- def param2pystr(p): if param_kind(p) == IN_ARRAY or param_kind(p) == OUT_ARRAY or param_kind(p) == IN_ARRAY or param_kind(p) == INOUT_ARRAY or param_kind(p) == OUT: @@ -260,6 +212,9 @@ def param2pystr(p): else: return type2pystr(param_type(p)) +# -------------- +# ML + def param2ml(p): k = param_kind(p) if k == OUT: @@ -510,6 +465,68 @@ def mk_dotnet_wrappers(dotnet): dotnet.write(" }\n\n") dotnet.write("}\n\n") +# ---------------------- +# Java + +Type2Java = { VOID : 'void', VOID_PTR : 'long', INT : 'int', UINT : 'int', INT64 : 'long', UINT64 : 'long', DOUBLE : 'double', + FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr', + BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'long' } + +Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', INT64 : 'jlong', UINT64 : 'jlong', DOUBLE : 'jdouble', + FLOAT : 'jfloat', STRING : 'jstring', STRING_PTR : 'jobject', + BOOL : 'jboolean', SYMBOL : 'jlong', PRINT_MODE : 'jint', ERROR_CODE : 'jint', CHAR : 'jchar', CHAR_PTR : 'jlong'} + +def type2java(ty): + global Type2Java + if (ty >= FIRST_OBJ_ID): + return 'long' + else: + return Type2Java[ty] + +def type2javaw(ty): + global Type2JavaW + if (ty >= FIRST_OBJ_ID): + return 'jlong' + else: + return Type2JavaW[ty] + +def param2java(p): + k = param_kind(p) + if k == OUT: + if param_type(p) == INT or param_type(p) == UINT: + return "IntPtr" + elif param_type(p) == INT64 or param_type(p) == UINT64 or param_type(p) == VOID_PTR or param_type(p) >= FIRST_OBJ_ID: + return "LongPtr" + elif param_type(p) == STRING: + return "StringPtr" + else: + print("ERROR: unreachable code") + assert(False) + exit(1) + elif k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY: + return "%s[]" % type2java(param_type(p)) + elif k == OUT_MANAGED_ARRAY: + if param_type(p) == UINT: + return "UIntArrayPtr" + else: + return "ObjArrayPtr" + else: + return type2java(param_type(p)) + +def param2javaw(p): + k = param_kind(p) + if k == OUT: + return "jobject" + elif k == IN_ARRAY or k == INOUT_ARRAY or k == OUT_ARRAY: + if param_type(p) == INT or param_type(p) == UINT or param_type(p) == BOOL: + return "jintArray" + else: + return "jlongArray" + elif k == OUT_MANAGED_ARRAY: + return "jlong" + else: + return type2javaw(param_type(p)) + def java_method_name(name): result = '' name = name[3:] # Remove Z3_ @@ -792,6 +809,10 @@ def mk_log_header(file, name, params): i = i + 1 file.write(")") +# --------------------------------- +# Logging + + def log_param(p): kind = param_kind(p) ty = param_type(p) @@ -1882,6 +1903,7 @@ def generate_files(api_files, import tempfile return tempfile.TemporaryFile(mode=mode) + defT = DefTypes() with mk_file_or_temp(api_output_dir, 'api_log_macros.h') as log_h: with mk_file_or_temp(api_output_dir, 'api_log_macros.cpp') as log_c: with mk_file_or_temp(api_output_dir, 'api_commands.cpp') as exe_c: @@ -1893,7 +1915,7 @@ def generate_files(api_files, write_core_py_preamble(core_py) # FIXME: these functions are awful - def_Types(api_files) + defT.def_Types(api_files) def_APIs(api_files) mk_bindings(exe_c) mk_py_wrappers() From 5ec7a66a453e55af5c71591871672637be2b3c11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 22:02:14 -0800 Subject: [PATCH 77/88] change class name, add comment --- scripts/update_api.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index aa44c19e2..2daf0a7a7 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -88,11 +88,16 @@ Type2ML = { VOID : 'unit', VOID_PTR : 'VOIDP', INT : 'int', UINT : 'int', INT64 FLOAT : 'float', STRING : 'string', STRING_PTR : 'char**', BOOL : 'bool', SYMBOL : 'z3_symbol', PRINT_MODE : 'int', ERROR_CODE : 'int', CHAR : 'char', CHAR_PTR : 'string' } -class DefTypes: +class APITypes: def __init__(self): self.next_type_id = FIRST_OBJ_ID def def_Type(self, var, c_type, py_type): + """Process type definitions of the form def_Type(var, c_type, py_type) + The variable 'var' is set to a unique number and recorded globally using exec + It is used by 'def_APIs' to that uses the unique numbers to access the + corresponding C and Python types. + """ id = self.next_type_id exec('%s = %s' % (var, id), globals()) Type2Str[id] = c_type @@ -128,8 +133,6 @@ def type2dotnet(ty): global Type2Dotnet return Type2Dotnet[ty] - - def type2ml(ty): global Type2ML q = Type2ML[ty] @@ -1903,7 +1906,7 @@ def generate_files(api_files, import tempfile return tempfile.TemporaryFile(mode=mode) - defT = DefTypes() + apiTypes = APITypes() with mk_file_or_temp(api_output_dir, 'api_log_macros.h') as log_h: with mk_file_or_temp(api_output_dir, 'api_log_macros.cpp') as log_c: with mk_file_or_temp(api_output_dir, 'api_commands.cpp') as exe_c: @@ -1915,7 +1918,7 @@ def generate_files(api_files, write_core_py_preamble(core_py) # FIXME: these functions are awful - defT.def_Types(api_files) + apiTypes.def_Types(api_files) def_APIs(api_files) mk_bindings(exe_c) mk_py_wrappers() From bd8de964f737dc0e7c3b8fa739771fbf643bc926 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jan 2022 22:02:28 -0800 Subject: [PATCH 78/88] more fixes on relevancy --- src/sat/smt/euf_model.cpp | 4 ++++ src/sat/smt/euf_relevancy.cpp | 41 +++++++++++++++++++++++++++++------ src/sat/smt/euf_relevancy.h | 8 +++++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 3d0369287..9540cd016 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -199,6 +199,8 @@ namespace euf { expr* e = n->get_expr(); if (!is_app(e)) continue; + if (!is_relevant(n)) + continue; app* a = to_app(e); func_decl* f = a->get_decl(); if (!include_func_interp(f)) @@ -297,6 +299,8 @@ namespace euf { ev.set_model_completion(true); TRACE("model", for (enode* n : m_egraph.nodes()) { + if (!is_relevant(n)) + continue; unsigned id = n->get_root_id(); expr* val = m_values.get(id, nullptr); if (!val) diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index a24277293..66ed9054c 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -132,6 +132,35 @@ namespace euf { m_trail.push_back(std::make_pair(update::relevant_var, lit.var())); } + void relevancy::set_asserted(sat::literal lit) { + SASSERT(!is_relevant(lit)); + SASSERT(ctx.s().value(lit) == l_true); + set_relevant(lit); + add_to_propagation_queue(lit); + ctx.asserted(lit); + } + + /** + * Boolean variable is set relevant because an E-node is relevant. + * + */ + void relevancy::relevant_eh(sat::bool_var v) { + if (is_relevant(v)) + return; + sat::literal lit(v); + switch (ctx.s().value(lit)) { + case l_undef: + set_relevant(lit); + break; + case l_true: + set_asserted(lit); + break; + case l_false: + set_asserted(~lit); + break; + } + } + void relevancy::asserted(sat::literal lit) { TRACE("relevancy", tout << "asserted " << lit << " relevant " << is_relevant(lit) << "\n"); if (!m_enabled) @@ -239,11 +268,8 @@ namespace euf { } } - if (true_lit != sat::null_literal) { - set_relevant(true_lit); - add_to_propagation_queue(true_lit); - ctx.asserted(true_lit); - } + if (true_lit != sat::null_literal) + set_asserted(true_lit); else { m_trail.push_back(std::make_pair(update::set_root, idx)); m_roots[idx] = true; @@ -276,8 +302,9 @@ namespace euf { if (!n->is_relevant()) { ctx.get_egraph().set_relevant(n); ctx.relevant_eh(n); - if (n->bool_var() != sat::null_bool_var) - mark_relevant(sat::literal(n->bool_var())); + sat::bool_var v = n->bool_var(); + if (v != sat::null_bool_var) + relevant_eh(v); for (euf::enode* sib : euf::enode_class(n)) if (!sib->is_relevant()) m_todo.push_back(sib); diff --git a/src/sat/smt/euf_relevancy.h b/src/sat/smt/euf_relevancy.h index b64b1d7f8..382b054fc 100644 --- a/src/sat/smt/euf_relevancy.h +++ b/src/sat/smt/euf_relevancy.h @@ -139,10 +139,14 @@ namespace euf { void add_to_propagation_queue(sat::literal lit); - void propagate_relevant(euf::enode* n); - void set_relevant(sat::literal lit); + void set_asserted(sat::literal lit); + + void relevant_eh(sat::bool_var v); + + void propagate_relevant(euf::enode* n); + public: relevancy(euf::solver& ctx): ctx(ctx) {} From d7c7fbb8f1b06e30bffcdc520666053b01a053d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 5 Jan 2022 21:16:25 -0800 Subject: [PATCH 79/88] setting roots breaks relevancy propagation --- src/cmd_context/cmd_context.cpp | 15 +++++++++++++++ src/sat/smt/euf_relevancy.cpp | 1 + src/sat/smt/euf_solver.cpp | 2 ++ src/smt/smt_relevancy.cpp | 12 ++++++------ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 845ac645c..968dcacd8 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -2107,6 +2107,21 @@ void cmd_context::analyze_failure(expr_mark& seen, model_evaluator& ev, expr* a, << (expected_value?"true":"false") << "\n";); IF_VERBOSE(11, display_detailed_analysis(verbose_stream(), ev, a)); + + if (m().is_iff(a)) { + ptr_vector todo; + todo.push_back(a); + for (unsigned i = 0; i < todo.size(); ++i) { + e = todo[i]; + if (m().is_and(e) || m().is_or(e) || m().is_iff(e) || m().is_implies(e) || m().is_not(e)) + for (expr* arg : *to_app(e)) + todo.push_back(arg); + else + IF_VERBOSE(10, verbose_stream() << "#" << e->get_id() << " " << mk_bounded_pp(e, m()) << " " << (ev.is_true(e)?"true":"false") << "\n"); + } + return; + } + } void cmd_context::display_detailed_analysis(std::ostream& out, model_evaluator& ev, expr* e) { diff --git a/src/sat/smt/euf_relevancy.cpp b/src/sat/smt/euf_relevancy.cpp index 66ed9054c..73fe49506 100644 --- a/src/sat/smt/euf_relevancy.cpp +++ b/src/sat/smt/euf_relevancy.cpp @@ -73,6 +73,7 @@ namespace euf { if (!m_enabled) return; flush(); + TRACE("relevancy", tout << "root " << sat::literal_vector(n, lits) << "\n"); sat::literal true_lit = sat::null_literal; for (unsigned i = 0; i < n; ++i) { if (ctx.s().value(lits[i]) == l_true) { diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index 7c8a42bf1..bb2d61b0a 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -806,6 +806,8 @@ namespace euf { } bool solver::set_root(literal l, literal r) { + if (m_relevancy.enabled()) + return false; expr* e = bool_var2expr(l.var()); if (!e) return true; diff --git a/src/smt/smt_relevancy.cpp b/src/smt/smt_relevancy.cpp index 9ad2a17ed..4b787561d 100644 --- a/src/smt/smt_relevancy.cpp +++ b/src/smt/smt_relevancy.cpp @@ -134,11 +134,11 @@ namespace smt { obj_map m_relevant_ehs; obj_map m_watches[2]; struct eh_trail { - enum kind { POS_WATCH, NEG_WATCH, HANDLER }; + enum class kind { POS_WATCH, NEG_WATCH, HANDLER }; kind m_kind; expr * m_node; - eh_trail(expr * n):m_kind(HANDLER), m_node(n) {} - eh_trail(expr * n, bool val):m_kind(val ? POS_WATCH : NEG_WATCH), m_node(n) {} + eh_trail(expr * n):m_kind(kind::HANDLER), m_node(n) {} + eh_trail(expr * n, bool val):m_kind(val ? kind::POS_WATCH : kind::NEG_WATCH), m_node(n) {} kind get_kind() const { return m_kind; } expr * get_node() const { return m_node; } }; @@ -292,9 +292,9 @@ namespace smt { expr * n = t.get_node(); relevancy_ehs * ehs; switch (t.get_kind()) { - case eh_trail::POS_WATCH: ehs = get_watches(n, true); SASSERT(ehs); set_watches(n, true, ehs->tail()); break; - case eh_trail::NEG_WATCH: ehs = get_watches(n, false); SASSERT(ehs); set_watches(n, false, ehs->tail()); break; - case eh_trail::HANDLER: ehs = get_handlers(n); SASSERT(ehs); set_handlers(n, ehs->tail()); break; + case eh_trail::kind::POS_WATCH: ehs = get_watches(n, true); SASSERT(ehs); set_watches(n, true, ehs->tail()); break; + case eh_trail::kind::NEG_WATCH: ehs = get_watches(n, false); SASSERT(ehs); set_watches(n, false, ehs->tail()); break; + case eh_trail::kind::HANDLER: ehs = get_handlers(n); SASSERT(ehs); set_handlers(n, ehs->tail()); break; default: UNREACHABLE(); break; } m.dec_ref(n); From 130a0c4aa0587ab679ec6fa5ea3b57f843f91373 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 08:34:45 -0800 Subject: [PATCH 80/88] resurrect infinitesimals from maximization function #5720 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 39a7bb032..f184a818c 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -259,6 +259,9 @@ namespace opt { if (!m_models[i]) m_models.set(i, m_last_model.get()); + if (val > m_objective_values[i]) + m_objective_values[i] = val; + // // retrieve value of objective from current model and update // current optimal. @@ -267,7 +270,7 @@ namespace opt { rational r; expr_ref value = (*m_last_model)(m_objective_terms.get(i)); if (arith_util(m).is_numeral(value, r) && r > m_objective_values[i]) - m_objective_values[i] = inf_eps(r); + m_objective_values[i] = inf_eps(r); }; update_objective(); From dadda86bdc3202ed0b73603ba500c19c4363fd06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 11:43:17 -0800 Subject: [PATCH 81/88] #5751 --- src/opt/optsmt.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 21489be58..966c6efef 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -49,14 +49,14 @@ namespace opt { dst[i] = src[i]; m_models.set(i, m_s->get_model_idx(i)); m_s->get_labels(m_labels); - m_lower_fmls[i] = fmls[i].get(); + m_lower_fmls[i] = fmls.get(i); if (dst[i].is_pos() && !dst[i].is_finite()) { // review: likely done already. m_lower_fmls[i] = m.mk_false(); fmls[i] = m.mk_false(); } } - else if (src[i] < dst[i] && !m.is_true(m_lower_fmls[i].get())) { - fmls[i] = m_lower_fmls[i].get(); + else if (src[i] < dst[i] && !m.is_true(m_lower_fmls.get(i))) { + fmls[i] = m_lower_fmls.get(i); } } } @@ -202,6 +202,9 @@ namespace opt { for (unsigned i = 0; i < obj_index; ++i) commit_assignment(i); + bound = update_lower(); + m_s->assert_expr(bound); + unsigned steps = 0; unsigned step_incs = 0; rational delta_per_step(1); @@ -282,7 +285,7 @@ namespace opt { bool optsmt::can_increment_delta(vector const& lower, unsigned i) { arith_util arith(m); inf_eps max_delta; - if (m_lower[i] < m_upper[i] && arith.is_int(m_objs[i].get())) { + if (m_lower[i] < m_upper[i] && arith.is_int(m_objs.get(i))) { inf_eps delta = m_lower[i] - lower[i]; if (m_lower[i].is_finite() && delta > max_delta) { return true; @@ -435,7 +438,7 @@ namespace opt { bool progress = false; for (unsigned i = 0; i < m_lower.size() && m.inc(); ++i) { if (m_lower[i] <= mid[i] && mid[i] <= m_upper[i] && m_lower[i] < m_upper[i]) { - th.enable_record_conflict(bounds[i].get()); + th.enable_record_conflict(bounds.get(i)); lbool is_sat = m_s->check_sat(1, bounds.data() + i); switch(is_sat) { case l_true: @@ -484,10 +487,10 @@ namespace opt { } for (unsigned i = 0; i < m_objs.size(); ++i) { - smt::theory_var v = solver.add_objective(m_objs[i].get()); + smt::theory_var v = solver.add_objective(m_objs.get(i)); if (v == smt::null_theory_var) { std::ostringstream out; - out << "Objective function '" << mk_pp(m_objs[i].get(), m) << "' is not supported"; + out << "Objective function '" << mk_pp(m_objs.get(i), m) << "' is not supported"; throw default_exception(out.str()); } m_vars.push_back(v); @@ -547,7 +550,7 @@ namespace opt { // force lower_bound(i) <= objective_value(i) void optsmt::commit_assignment(unsigned i) { inf_eps lo = m_lower[i]; - TRACE("opt", tout << "set lower bound of " << mk_pp(m_objs[i].get(), m) << " to: " << lo << "\n"; + TRACE("opt", tout << "set lower bound of " << mk_pp(m_objs.get(i), m) << " to: " << lo << "\n"; tout << get_lower(i) << ":" << get_upper(i) << "\n";); // Only assert bounds for bounded objectives if (lo.is_finite()) { From d14f00d61abd697c5ae03dd1e8079f272d72ad45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 13:02:13 -0800 Subject: [PATCH 82/88] with no last model Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index f184a818c..01975464a 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -260,7 +260,10 @@ namespace opt { m_models.set(i, m_last_model.get()); if (val > m_objective_values[i]) - m_objective_values[i] = val; + m_objective_values[i] = val; + + if (!m_last_model) + return true; // // retrieve value of objective from current model and update From 592b1d7f65506feb9a4c0ba5717a625ce8f4eede Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 13:32:50 -0800 Subject: [PATCH 83/88] #5752 --- src/smt/smt_enode.h | 1 - src/smt/smt_internalizer.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 6e739a499..8995f7fba 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -158,7 +158,6 @@ namespace smt { void mark_as_interpreted() { SASSERT(!m_interpreted); - SASSERT(m_owner->get_num_args() == 0); SASSERT(m_class_size == 1); m_interpreted = true; } diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 77b3f14d5..1c899ef18 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -974,7 +974,7 @@ namespace smt { } enode * e = enode::mk(m, m_region, m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl, cgc_enabled, true); TRACE("mk_enode_detail", tout << "e.get_num_args() = " << e->get_num_args() << "\n";); - if (n->get_num_args() == 0 && m.is_unique_value(n)) + if (m.is_unique_value(n)) e->mark_as_interpreted(); TRACE("mk_var_bug", tout << "mk_enode: " << id << "\n";); TRACE("generation", tout << "mk_enode: " << id << " " << generation << "\n";); From 6a3fe514f0a2c42a45fc33a0ae2b8b549b4125ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 14:07:54 -0800 Subject: [PATCH 84/88] build Signed-off-by: Nikolaj Bjorner --- src/opt/optsmt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 966c6efef..1063d2582 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -202,7 +202,7 @@ namespace opt { for (unsigned i = 0; i < obj_index; ++i) commit_assignment(i); - bound = update_lower(); + m_s->maximize_objective(obj_index, bound); m_s->assert_expr(bound); unsigned steps = 0; From 2be71cfc43c80a03b9bc680190b5fe8019ff8e47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 15:17:37 -0800 Subject: [PATCH 85/88] #5753 --- src/sat/smt/arith_internalize.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 882dd23b0..d81efc43b 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -545,11 +545,13 @@ namespace arith { } m_left_side.clear(); // reset the coefficients after they have been used. - for (unsigned i = 0; i < vars.size(); ++i) { - theory_var var = vars[i]; + for (theory_var var : vars) { rational const& r = m_columns[var]; if (!r.is_zero()) { - m_left_side.push_back(std::make_pair(r, register_theory_var_in_lar_solver(var))); + auto vi = register_theory_var_in_lar_solver(var); + if (lp::tv::is_term(vi)) + vi = lp().map_term_index_to_column_index(vi); + m_left_side.push_back(std::make_pair(r, vi)); m_columns[var].reset(); } } From 7baa4f88b0cb4458461596d147e1f71853d77126 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 6 Jan 2022 15:17:57 -0800 Subject: [PATCH 86/88] build failure --- src/opt/optsmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index 1063d2582..58cdd0cda 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -202,8 +202,8 @@ namespace opt { for (unsigned i = 0; i < obj_index; ++i) commit_assignment(i); - m_s->maximize_objective(obj_index, bound); - m_s->assert_expr(bound); +// m_s->maximize_objective(obj_index, bound); +// m_s->assert_expr(bound); unsigned steps = 0; unsigned step_incs = 0; From 199daead50fcc7f36d8a13185168e52944c266f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Jan 2022 11:52:10 -0800 Subject: [PATCH 87/88] remove Z3_bool_opt #5757 Signed-off-by: Nikolaj Bjorner --- src/api/api_config_params.cpp | 2 +- src/api/z3_api.h | 6 +++--- src/api/z3_macros.h | 3 --- src/ast/rewriter/bool_rewriter.cpp | 8 ++++---- src/sat/smt/q_mam.cpp | 18 ++++++++++++------ src/sat/smt/q_queue.cpp | 16 +++++++++------- src/smt/qi_queue.cpp | 8 ++++++++ 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index fd7c94f22..1b551bd73 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -47,7 +47,7 @@ extern "C" { env_params::updt_params(); } - Z3_bool_opt Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { + Z3_bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value) { memory::initialize(UINT_MAX); LOG_Z3_global_param_get(param_id, param_value); *param_value = nullptr; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d5bd1e11c..3f964adc6 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1516,7 +1516,7 @@ extern "C" { def_API('Z3_global_param_get', BOOL, (_in(STRING), _out(STRING))) */ - Z3_bool_opt Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value); + Z3_bool Z3_API Z3_global_param_get(Z3_string param_id, Z3_string_ptr param_value); /**@}*/ @@ -4325,7 +4325,7 @@ extern "C" { def_API('Z3_get_finite_domain_sort_size', BOOL, (_in(CONTEXT), _in(SORT), _out(UINT64))) */ - Z3_bool_opt Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t* r); + Z3_bool Z3_API Z3_get_finite_domain_sort_size(Z3_context c, Z3_sort s, uint64_t* r); /** \brief Return the domain of the given array sort. @@ -5264,7 +5264,7 @@ extern "C" { def_API('Z3_model_eval', BOOL, (_in(CONTEXT), _in(MODEL), _in(AST), _in(BOOL), _out(AST))) */ - Z3_bool_opt Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); + Z3_bool Z3_API Z3_model_eval(Z3_context c, Z3_model m, Z3_ast t, bool model_completion, Z3_ast * v); /** \brief Return the interpretation (i.e., assignment) of constant \c a in the model \c m. diff --git a/src/api/z3_macros.h b/src/api/z3_macros.h index d1ac18804..d42eb508a 100644 --- a/src/api/z3_macros.h +++ b/src/api/z3_macros.h @@ -4,9 +4,6 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#ifndef Z3_bool_opt -#define Z3_bool_opt Z3_bool -#endif #ifndef Z3_API # ifdef __GNUC__ diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 4c2ed7e12..1e58db340 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -722,12 +722,12 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { return BR_DONE; } - if (m().is_not(rhs)) + if (m().is_not(rhs)) std::swap(lhs, rhs); - if (m().is_not(lhs, lhs)) { - result = m().mk_not(m().mk_eq(lhs, rhs)); - return BR_REWRITE2; + if (m().is_not(lhs, lhs)) { + result = m().mk_not(m().mk_eq(lhs, rhs)); + return BR_REWRITE2; } if (unfolded) { diff --git a/src/sat/smt/q_mam.cpp b/src/sat/smt/q_mam.cpp index a968314c2..3debc3e47 100644 --- a/src/sat/smt/q_mam.cpp +++ b/src/sat/smt/q_mam.cpp @@ -424,15 +424,19 @@ namespace q { friend class compiler; friend class code_tree_manager; - void display_seq(std::ostream & out, instruction * head, unsigned indent) const { - for (unsigned i = 0; i < indent; i++) { + void spaces(std::ostream& out, unsigned indent) const { + for (unsigned i = 0; i < indent; i++) out << " "; - } + } + + void display_seq(std::ostream & out, instruction * head, unsigned indent) const { + spaces(out, indent); instruction * curr = head; out << *curr; curr = curr->m_next; while (curr != nullptr && curr->m_opcode != CHOOSE && curr->m_opcode != NOOP) { out << "\n"; + spaces(out, indent); out << *curr; curr = curr->m_next; } @@ -598,7 +602,7 @@ namespace q { ast_manager & m = m_egraph->get_manager(); out << "patterns:\n"; for (auto [q, a] : m_patterns) - out << mk_pp(q, m) << " " << mk_pp(a, m) << "\n"; + out << q->get_id() << ": " << mk_pp(q, m) << " " << mk_pp(a, m) << "\n"; } #endif out << "function: " << m_root_lbl->get_name(); @@ -2878,8 +2882,10 @@ namespace q { if (tree->expected_num_args() == p->get_num_args()) m_compiler.insert(tree, qa, mp, first_idx, false); } - DEBUG_CODE(m_trees[lbl_id]->get_patterns().push_back(std::make_pair(qa, mp)); - ctx.push(push_back_trail, false>(m_trees[lbl_id]->get_patterns()));); + DEBUG_CODE(if (first_idx == 0) { + m_trees[lbl_id]->get_patterns().push_back(std::make_pair(qa, mp)); + ctx.push(push_back_trail, false>(m_trees[lbl_id]->get_patterns())); + }); TRACE("trigger_bug", tout << "after add_pattern, first_idx: " << first_idx << "\n"; m_trees[lbl_id]->display(tout);); } diff --git a/src/sat/smt/q_queue.cpp b/src/sat/smt/q_queue.cpp index d74ee4e39..c30009127 100644 --- a/src/sat/smt/q_queue.cpp +++ b/src/sat/smt/q_queue.cpp @@ -149,12 +149,7 @@ namespace q { if (false && em.propagate(true, f.nodes(), gen, *f.c, new_propagation)) return; -#if 0 - std::cout << mk_pp(q, m) << "\n"; - std::cout << num_bindings << "\n"; - for (unsigned i = 0; i < num_bindings; ++i) - std::cout << mk_pp(f[i]->get_expr(), m) << " " << mk_pp(f[i]->get_sort(), m) << "\n"; -#endif + auto* ebindings = m_subst(q, num_bindings); for (unsigned i = 0; i < num_bindings; ++i) ebindings[i] = f[i]->get_expr(); @@ -168,7 +163,14 @@ namespace q { m_stats.m_num_instances++; - // f.display(ctx, std::cout << mk_pp(f.q(), m) << "\n" << instance << "\n") << "\n"; + std::cout << "instantiate\n"; + for (unsigned i = 0; i < num_bindings; ++i) + std::cout << ctx.bpp(f[i]) << " "; + std::cout << "\n"; + std::cout << mk_pp(q, m) << "\n"; + + +// f.display(ctx, std::cout << mk_pp(f.q(), m) << "\n" << instance << "\n") << "\n"; euf::solver::scoped_generation _sg(ctx, gen); diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index f359136af..7c21c1362 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -226,6 +226,7 @@ namespace smt { ebindings[i] = bindings[i]->get_expr(); expr_ref instance = m_subst(); + TRACE("qi_queue", tout << "new instance:\n" << mk_pp(instance, m) << "\n";); TRACE("qi_queue_instance", tout << "new instance:\n" << mk_pp(instance, m) << "\n";); expr_ref s_instance(m); @@ -244,6 +245,13 @@ namespace smt { return; } + std::cout << "instantiate\n"; + enode_vector _bindings(num_bindings, bindings); + for (auto * b : _bindings) + std::cout << enode_pp(b, m_context) << " "; + std::cout << "\n"; + std::cout << mk_pp(q, m) << "\n"; + TRACE("qi_queue", tout << "simplified instance:\n" << s_instance << "\n";); stat->inc_num_instances(); if (stat->get_num_instances() % m_params.m_qi_profile_freq == 0) { From 0bc8518cb5277e38b462c5a667945456ffb2e1b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 7 Jan 2022 11:53:27 -0800 Subject: [PATCH 88/88] na Signed-off-by: Nikolaj Bjorner --- src/sat/smt/q_queue.cpp | 3 ++- src/smt/qi_queue.cpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/q_queue.cpp b/src/sat/smt/q_queue.cpp index c30009127..ff7dbc8ab 100644 --- a/src/sat/smt/q_queue.cpp +++ b/src/sat/smt/q_queue.cpp @@ -163,12 +163,13 @@ namespace q { m_stats.m_num_instances++; +#if 0 std::cout << "instantiate\n"; for (unsigned i = 0; i < num_bindings; ++i) std::cout << ctx.bpp(f[i]) << " "; std::cout << "\n"; std::cout << mk_pp(q, m) << "\n"; - +#endif // f.display(ctx, std::cout << mk_pp(f.q(), m) << "\n" << instance << "\n") << "\n"; diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 7c21c1362..1cef2a0f1 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -245,13 +245,15 @@ namespace smt { return; } +#if 0 std::cout << "instantiate\n"; enode_vector _bindings(num_bindings, bindings); for (auto * b : _bindings) std::cout << enode_pp(b, m_context) << " "; std::cout << "\n"; std::cout << mk_pp(q, m) << "\n"; - +#endif + TRACE("qi_queue", tout << "simplified instance:\n" << s_instance << "\n";); stat->inc_num_instances(); if (stat->get_num_instances() % m_params.m_qi_profile_freq == 0) {