From 7585f28dec4e460cee54665585b25cd02bfbf532 Mon Sep 17 00:00:00 2001 From: Nils Becker Date: Sun, 8 Apr 2018 18:16:38 +0200 Subject: [PATCH 001/118] Improved quantifier instantiation logging --- src/smt/mam.cpp | 27 ++++++------ src/smt/mam.h | 3 +- src/smt/smt_context.cpp | 5 ++- src/smt/smt_context.h | 3 +- src/smt/smt_enode.cpp | 1 + src/smt/smt_enode.h | 6 +++ src/smt/smt_model_checker.cpp | 3 +- src/smt/smt_quantifier.cpp | 78 ++++++++++++++++++++++++++++++++--- src/smt/smt_quantifier.h | 3 +- src/smt/smt_quick_checker.cpp | 3 +- 10 files changed, 108 insertions(+), 24 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 5c881684f..acd21f9a2 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1866,7 +1866,7 @@ namespace smt { enode * m_n2; enode * m_app; const bind * m_b; - ptr_vector m_used_enodes; + vector> m_used_enodes; unsigned m_curr_used_enodes_size; ptr_vector m_pattern_instances; // collect the pattern instances... used for computing min_top_generation and max_top_generation unsigned_vector m_min_top_generation, m_max_top_generation; @@ -1883,11 +1883,11 @@ namespace smt { m_pool.recycle(v); } - void update_max_generation(enode * n) { + void update_max_generation(enode * n, enode * prev) { m_max_generation = std::max(m_max_generation, n->get_generation()); if (m_ast_manager.has_trace_stream()) - m_used_enodes.push_back(n); + m_used_enodes.push_back(std::make_tuple(prev, n)); } // We have to provide the number of expected arguments because we have flat-assoc applications such as +. @@ -1896,7 +1896,7 @@ namespace smt { enode * first = curr; do { if (curr->get_decl() == lbl && curr->is_cgr() && curr->get_num_args() == num_expected_args) { - update_max_generation(curr); + update_max_generation(curr, first); return curr; } curr = curr->get_next(); @@ -1909,7 +1909,7 @@ namespace smt { curr = curr->get_next(); while (curr != first) { if (curr->get_decl() == lbl && curr->is_cgr() && curr->get_num_args() == num_expected_args) { - update_max_generation(curr); + update_max_generation(curr, first); return curr; } curr = curr->get_next(); @@ -1933,7 +1933,7 @@ namespace smt { do { if (n->get_decl() == f && n->get_arg(0)->get_root() == m_args[0]) { - update_max_generation(n); + update_max_generation(n, first); return true; } n = n->get_next(); @@ -1948,7 +1948,7 @@ namespace smt { if (n->get_decl() == f && n->get_arg(0)->get_root() == m_args[0] && n->get_arg(1)->get_root() == m_args[1]) { - update_max_generation(n); + update_max_generation(n, first); return true; } n = n->get_next(); @@ -1968,7 +1968,7 @@ namespace smt { break; } if (i == num_args) { - update_max_generation(n); + update_max_generation(n, first); return true; } } @@ -2213,7 +2213,7 @@ namespace smt { if (bp.m_it == bp.m_end) return nullptr; m_top++; - update_max_generation(*(bp.m_it)); + update_max_generation(*(bp.m_it), nullptr); return *(bp.m_it); } @@ -2294,7 +2294,7 @@ namespace smt { if (m_ast_manager.has_trace_stream()) { m_used_enodes.reset(); - m_used_enodes.push_back(n); + m_used_enodes.push_back(std::make_tuple(nullptr, n)); } m_pc = t->get_root(); @@ -2399,6 +2399,9 @@ namespace smt { SASSERT(m_n2 != 0); if (m_n1->get_root() != m_n2->get_root()) goto backtrack; + + m_used_enodes.push_back(std::make_tuple(m_n1, m_n2)); + m_pc = m_pc->m_next; goto main_loop; @@ -2793,7 +2796,7 @@ namespace smt { m_pattern_instances.pop_back(); m_pattern_instances.push_back(m_app); // continue succeeded - update_max_generation(m_app); + update_max_generation(m_app, nullptr); TRACE("mam_int", tout << "continue next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); m_num_args = c->m_num_args; m_oreg = c->m_oreg; @@ -3932,7 +3935,7 @@ namespace smt { } #endif - void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) override { + void on_match(quantifier * qa, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, vector> & used_enodes) override { TRACE("trigger_bug", tout << "found match " << mk_pp(qa, m_ast_manager) << "\n";); #ifdef Z3DEBUG if (m_check_missing_instances) { diff --git a/src/smt/mam.h b/src/smt/mam.h index 635cb30e7..f6b2958c5 100644 --- a/src/smt/mam.h +++ b/src/smt/mam.h @@ -21,6 +21,7 @@ Revision History: #include "ast/ast.h" #include "smt/smt_types.h" +#include namespace smt { /** @@ -57,7 +58,7 @@ namespace smt { virtual void display(std::ostream& out) = 0; - virtual void on_match(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, ptr_vector & used_enodes) = 0; + virtual void on_match(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, vector> & used_enodes) = 0; virtual bool is_shared(enode * n) const = 0; diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index dd38776bc..8a37ba61e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -558,6 +558,7 @@ namespace smt { invert_trans(n1); n1->m_trans.m_target = n2; n1->m_trans.m_justification = js; + n1->m_proof_is_logged = false; SASSERT(r1->trans_reaches(n1)); // --------------- // r1 -> .. -> n1 -> n2 -> ... -> r2 @@ -749,6 +750,7 @@ namespace smt { eq_justification new_js = curr->m_trans.m_justification; curr->m_trans.m_target = prev; curr->m_trans.m_justification = js; + curr->m_proof_is_logged = false; prev = curr; js = new_js; curr = new_curr; @@ -1045,6 +1047,7 @@ namespace smt { SASSERT(r1->trans_reaches(n1)); n1->m_trans.m_target = nullptr; n1->m_trans.m_justification = null_eq_justification; + n1->m_proof_is_logged = false; invert_trans(r1); // --------------- // n1 -> ... -> r1 @@ -1809,7 +1812,7 @@ namespace smt { } bool context::add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, - unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes) { + unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes) { return m_qmanager->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_top_generation, used_enodes); } diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index a4581b020..f4e7b72e0 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -49,6 +49,7 @@ Revision History: #include "util/timer.h" #include "util/statistics.h" #include "solver/progress_callback.h" +#include // there is a significant space overhead with allocating 1000+ contexts in // the case that each context only references a few expressions. @@ -946,7 +947,7 @@ namespace smt { bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, - unsigned min_top_generation, unsigned max_top_generation, ptr_vector & used_enodes); + unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes); void set_global_generation(unsigned generation) { m_generation = generation; } diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index e09e83f6b..d14c37906 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -47,6 +47,7 @@ namespace smt { n->m_cgc_enabled = cgc_enabled; n->m_iscope_lvl = iscope_lvl; n->m_lbl_hash = -1; + n->m_proof_is_logged = false; unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { enode * arg = app2enode[owner->get_arg(i)->get_id()]; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index b216665e5..d4aebd56b 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -105,6 +105,7 @@ namespace smt { enode_vector m_parents; //!< Parent enodes of the equivalence class. theory_var_list m_th_var_list; //!< List of theories that 'care' about this enode. trans_justification m_trans; //!< A justification for the enode being equal to its root. + bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log. signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern approx_set m_lbls; approx_set m_plbls; @@ -113,6 +114,7 @@ namespace smt { friend class context; friend class euf_manager; friend class conflict_resolution; + friend class quantifier_manager; theory_var_list * get_th_var_list() { @@ -317,6 +319,10 @@ namespace smt { theory_var get_th_var(theory_id th_id) const; + trans_justification get_trans_justification() { + return m_trans; + } + unsigned get_generation() const { return m_generation; } diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp index 765cc87f5..549c15148 100644 --- a/src/smt/smt_model_checker.cpp +++ b/src/smt/smt_model_checker.cpp @@ -26,6 +26,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/smt_model_finder.h" #include "model/model_pp.h" +#include namespace smt { @@ -476,7 +477,7 @@ namespace smt { void model_checker::assert_new_instances() { TRACE("model_checker_bug_detail", tout << "assert_new_instances, inconsistent: " << m_context->inconsistent() << "\n";); ptr_buffer bindings; - ptr_vector dummy; + vector> dummy; for (instance* inst : m_new_instances) { quantifier * q = inst->m_q; if (m_context->b_internalized(q)) { diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 0ca244185..19fe2c14a 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -104,13 +104,64 @@ namespace smt { return m_plugin->is_shared(n); } + inline void log_transitive_justification(std::ostream & log, enode *en) { + enode *root = en->get_root(); + for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { + if (!it->m_proof_is_logged) { + it->m_proof_is_logged = true; + print_justification(log, it); + } + } + if (!root->m_proof_is_logged) { + root->m_proof_is_logged = true; + log << "[eq-expl] #" << root->get_owner_id() << " root\n"; + } + } + + inline void print_justification(std::ostream & out, enode *en) { + smt::literal lit; + unsigned num_args; + enode *target = en->get_trans_justification().m_target; + + switch (en->get_trans_justification().m_justification.get_kind()) { + case smt::eq_justification::kind::EQUATION: + lit = en->get_trans_justification().m_justification.get_literal(); + out << "[eq-expl] #" << en->get_owner_id() << " lit #" << m_context.bool_var2expr(lit.var())->get_id() << " ; #" << target->get_owner_id() << "\n"; + break; + case smt::eq_justification::kind::AXIOM: + out << "[eq-expl] #" << en->get_owner_id() << " ax ; #" << target->get_owner_id() << "\n"; + break; + case smt::eq_justification::kind::CONGRUENCE: + if (!en->get_trans_justification().m_justification.used_commutativity()) { + num_args = en->get_num_args(); + + for (unsigned i = 0; i < num_args; i++) { + + log_transitive_justification(out, en->get_arg(i)); + log_transitive_justification(out, target->get_arg(i)); + } + + out << "[eq-expl] #" << en->get_owner_id() << " cg"; + for (unsigned i = 0; i < num_args; i++) { + out << " (#" << en->get_arg(i)->get_owner_id() << " #" << target->get_arg(i)->get_owner_id() << ")"; + } + out << " ; #" << target->get_owner_id() << "\n"; + + break; + } + default: + out << "[eq-expl] #" << en->get_owner_id() << " nyi ; #" << target->get_owner_id() << "\n"; + break; + } + } + bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes) { + vector> & used_enodes) { max_generation = std::max(max_generation, get_generation(q)); if (m_num_instances > m_params.m_qi_max_instances) { return false; @@ -120,15 +171,30 @@ namespace smt { if (f) { if (has_trace_stream()) { std::ostream & out = trace_stream(); - out << "[new-match] " << static_cast(f) << " #" << q->get_id(); + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig != nullptr) { + log_transitive_justification(out, orig); + log_transitive_justification(out, substituted); + } + } + out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); for (unsigned i = 0; i < num_bindings; i++) { // I don't want to use mk_pp because it creates expressions for pretty printing. // This nasty side-effect may change the behavior of Z3. out << " #" << bindings[i]->get_owner_id(); } out << " ;"; - for (enode* n : used_enodes) - out << " #" << n->get_owner_id(); + for (auto n : used_enodes) { + enode *orig = std::get<0>(n); + enode *substituted = std::get<1>(n); + if (orig == nullptr) + out << " #" << substituted->get_owner_id(); + else { + out << " (#" << orig->get_owner_id() << " #" << substituted->get_owner_id() << ")"; + } + } out << "\n"; } m_qi_queue.insert(f, pat, max_generation, min_top_generation, max_top_generation); // TODO @@ -294,12 +360,12 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes) { + vector> & used_enodes) { return m_imp->add_instance(q, pat, num_bindings, bindings, max_generation, min_top_generation, max_generation, used_enodes); } bool quantifier_manager::add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation) { - ptr_vector tmp; + vector> tmp; return add_instance(q, nullptr, num_bindings, bindings, generation, generation, generation, tmp); } diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index ad5f58e49..1b1c3547e 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -23,6 +23,7 @@ Revision History: #include "util/statistics.h" #include "util/params.h" #include "smt/smt_types.h" +#include class proto_model; struct smt_params; @@ -57,7 +58,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - ptr_vector & used_enodes); + vector> & used_enodes); bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0); void init_search_eh(); diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 64c791a0e..ab75d2dea 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/smt_quick_checker.h" #include "ast/ast_pp.h" +#include namespace smt { @@ -211,7 +212,7 @@ namespace smt { } bool quick_checker::process_candidates(quantifier * q, bool unsat) { - ptr_vector empty_used_enodes; + vector> empty_used_enodes; buffer szs; buffer it; for (unsigned i = 0; i < m_num_bindings; i++) { From 7a03f194567f1322dc0b6548c29fe102a92cea87 Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Sun, 29 Apr 2018 13:08:57 +0200 Subject: [PATCH 002/118] fixing smt code ending up in log files (verbose logging) --- src/smt/smt_context_pp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index f4f56df5d..f072a1d13 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -580,20 +580,20 @@ namespace smt { case b_justification::BIN_CLAUSE: { literal l2 = j.get_literal(); out << "bin-clause "; - display_literal_verbose(out, l2); + display_literal(out, l2); break; } case b_justification::CLAUSE: { clause * cls = j.get_clause(); out << "clause "; - if (cls) display_literals_verbose(out, cls->get_num_literals(), cls->begin_literals()); + if (cls) display_literals(out, cls->get_num_literals(), cls->begin_literals()); break; } case b_justification::JUSTIFICATION: { out << "justification " << j.get_justification()->get_from_theory() << ": "; literal_vector lits; const_cast(*m_conflict_resolution).justification2literals(j.get_justification(), lits); - display_literals_verbose(out, lits); + display_literals(out, lits); break; } default: From 9bc7d5de0f25728c9fd850b6329e4091283d07ab Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Sun, 29 Apr 2018 16:39:32 +0200 Subject: [PATCH 003/118] making sure equality explanations for bound terms are logged --- src/smt/smt_quantifier.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 5d7c82415..2b134a23f 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -171,6 +171,9 @@ namespace smt { if (f) { if (has_trace_stream()) { std::ostream & out = trace_stream(); + for (unsigned i = 0; i < num_bindings; ++i) { + log_transitive_justification(out, bindings[i]); + } for (auto n : used_enodes) { enode *orig = std::get<0>(n); enode *substituted = std::get<1>(n); From 1aeffa2e013e7b0d9ec00bf914ee7ad4e16cea1d Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Thu, 24 May 2018 19:25:59 +0200 Subject: [PATCH 004/118] fixing issue where argument equalities for congruence explanations were not updated explaining equalities added by theories --- src/smt/smt_context.cpp | 7 ++++--- src/smt/smt_enode.cpp | 2 +- src/smt/smt_enode.h | 11 +++++++++- src/smt/smt_quantifier.cpp | 42 ++++++++++++++++++++++++++++++-------- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index c378c401b..5b0b3eacd 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -562,7 +562,7 @@ namespace smt { invert_trans(n1); n1->m_trans.m_target = n2; n1->m_trans.m_justification = js; - n1->m_proof_is_logged = false; + n1->m_proof_logged_status = smt::logged_status::NOT_LOGGED; SASSERT(r1->trans_reaches(n1)); // --------------- // r1 -> .. -> n1 -> n2 -> ... -> r2 @@ -748,13 +748,14 @@ namespace smt { eq_justification js = n->m_trans.m_justification; prev->m_trans.m_target = nullptr; prev->m_trans.m_justification = null_eq_justification; + prev->m_proof_logged_status = smt::logged_status::NOT_LOGGED; while (curr != nullptr) { SASSERT(prev->trans_reaches(n)); enode * new_curr = curr->m_trans.m_target; eq_justification new_js = curr->m_trans.m_justification; curr->m_trans.m_target = prev; curr->m_trans.m_justification = js; - curr->m_proof_is_logged = false; + curr->m_proof_logged_status = smt::logged_status::NOT_LOGGED; prev = curr; js = new_js; curr = new_curr; @@ -1051,7 +1052,7 @@ namespace smt { SASSERT(r1->trans_reaches(n1)); n1->m_trans.m_target = nullptr; n1->m_trans.m_justification = null_eq_justification; - n1->m_proof_is_logged = false; + n1->m_proof_logged_status = smt::logged_status::NOT_LOGGED; invert_trans(r1); // --------------- // n1 -> ... -> r1 diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index d14c37906..ca646974d 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -47,7 +47,7 @@ namespace smt { n->m_cgc_enabled = cgc_enabled; n->m_iscope_lvl = iscope_lvl; n->m_lbl_hash = -1; - n->m_proof_is_logged = false; + n->m_proof_logged_status = smt::logged_status::NOT_LOGGED; unsigned num_args = n->get_num_args(); for (unsigned i = 0; i < num_args; i++) { enode * arg = app2enode[owner->get_arg(i)->get_id()]; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 7c1bb3e4d..3e7f0984d 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -38,6 +38,15 @@ namespace smt { } }; + /** + \brief Indicates whether the proof for membership in an equivalence class is already logged. + */ + enum logged_status { + NOT_LOGGED, + BEING_LOGGED, + LOGGED + }; + /** \ brief Use sparse maps in SMT solver. Define this to use hash maps rather than vectors over ast @@ -105,7 +114,7 @@ namespace smt { enode_vector m_parents; //!< Parent enodes of the equivalence class. theory_var_list m_th_var_list; //!< List of theories that 'care' about this enode. trans_justification m_trans; //!< A justification for the enode being equal to its root. - bool m_proof_is_logged; //!< Indicates that the proof for the enode being equal to its root is in the log. + logged_status m_proof_logged_status; //!< Indicates that the proof for the enode being equal to its root is in the log. signed char m_lbl_hash; //!< It is different from -1, if enode is used in a pattern approx_set m_lbls; approx_set m_plbls; diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 2b134a23f..d8795c0cf 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -104,24 +104,38 @@ namespace smt { return m_plugin->is_shared(n); } - inline void log_transitive_justification(std::ostream & log, enode *en) { + void log_transitive_justification(std::ostream & log, enode *en) { enode *root = en->get_root(); for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { - if (!it->m_proof_is_logged) { - it->m_proof_is_logged = true; + if (it->m_proof_logged_status == smt::logged_status::NOT_LOGGED) { + it->m_proof_logged_status = smt::logged_status::BEING_LOGGED; print_justification(log, it); + it->m_proof_logged_status = smt::logged_status::LOGGED; + } else if (it->m_proof_logged_status != smt::logged_status::BEING_LOGGED && it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { + + // When the justification of an argument changes m_proof_logged_status is not reset => We need to check if the proofs of all arguments are logged. + it->m_proof_logged_status = smt::logged_status::BEING_LOGGED; + const unsigned num_args = it->get_num_args(); + enode *target = it->get_trans_justification().m_target; + + for (unsigned i = 0; i < num_args; ++i) { + log_transitive_justification(log, it->get_arg(i)); + log_transitive_justification(log, target->get_arg(i)); + } + it->m_proof_logged_status = smt::logged_status::LOGGED; } } - if (!root->m_proof_is_logged) { - root->m_proof_is_logged = true; + if (root->m_proof_logged_status == smt::logged_status::NOT_LOGGED) { log << "[eq-expl] #" << root->get_owner_id() << " root\n"; + root->m_proof_logged_status = smt::logged_status::LOGGED; } } - inline void print_justification(std::ostream & out, enode *en) { + void print_justification(std::ostream & out, enode *en) { smt::literal lit; unsigned num_args; enode *target = en->get_trans_justification().m_target; + theory_id th_id; switch (en->get_trans_justification().m_justification.get_kind()) { case smt::eq_justification::kind::EQUATION: @@ -142,15 +156,27 @@ namespace smt { } out << "[eq-expl] #" << en->get_owner_id() << " cg"; - for (unsigned i = 0; i < num_args; i++) { + for (unsigned i = 0; i < num_args; ++i) { out << " (#" << en->get_arg(i)->get_owner_id() << " #" << target->get_arg(i)->get_owner_id() << ")"; } out << " ; #" << target->get_owner_id() << "\n"; + break; + } else { + out << "[eq-expl] #" << en->get_owner_id() << " nyi ; #" << target->get_owner_id() << "\n"; break; } + case smt::eq_justification::kind::JUSTIFICATION: + th_id = en->get_trans_justification().m_justification.get_justification()->get_from_theory(); + if (th_id != null_theory_id) { + symbol const theory = m().get_family_name(th_id); + out << "[eq-expl] #" << en->get_owner_id() << " th:" << theory.str() << " ; #" << target->get_owner_id() << "\n"; + } else { + out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; + } + break; default: - out << "[eq-expl] #" << en->get_owner_id() << " nyi ; #" << target->get_owner_id() << "\n"; + out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; break; } } From f3a627b02620c425765d99693cfa0dceeca819fa Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Sun, 27 May 2018 15:29:57 +0200 Subject: [PATCH 005/118] making theory explantions easier to parse --- src/smt/smt_quantifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index d8795c0cf..0951ab913 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -170,7 +170,7 @@ namespace smt { th_id = en->get_trans_justification().m_justification.get_justification()->get_from_theory(); if (th_id != null_theory_id) { symbol const theory = m().get_family_name(th_id); - out << "[eq-expl] #" << en->get_owner_id() << " th:" << theory.str() << " ; #" << target->get_owner_id() << "\n"; + out << "[eq-expl] #" << en->get_owner_id() << " th " << theory.str() << " ; #" << target->get_owner_id() << "\n"; } else { out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; } From 3c464071f7cde63ec67c36039fbe6155b90388b1 Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Wed, 6 Jun 2018 19:22:01 +0200 Subject: [PATCH 006/118] adding comments --- src/smt/mam.cpp | 2 +- src/smt/smt_enode.h | 6 +++--- src/smt/smt_quantifier.cpp | 35 +++++++++++++++++++++-------------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 4e8c3b922..caf677a85 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -2399,7 +2399,7 @@ namespace smt { SASSERT(m_n2 != 0); if (m_n1->get_root() != m_n2->get_root()) goto backtrack; - + m_used_enodes.push_back(std::make_tuple(m_n1, m_n2)); m_pc = m_pc->m_next; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 14f78e265..61fed786b 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -42,9 +42,9 @@ namespace smt { \brief Indicates whether the proof for membership in an equivalence class is already logged. */ enum logged_status { - NOT_LOGGED, - BEING_LOGGED, - LOGGED + NOT_LOGGED, //!< Proof is not logged or logged information is not up-to-date. + BEING_LOGGED, //!< We are currently in the process of logging all relevant information. This is used to prevent looping when logging congruence steps. + LOGGED //!< Proof is logged and logged information is still up-to-date. }; /** \ brief Use sparse maps in SMT solver. diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 0951ab913..63297f829 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -104,12 +104,16 @@ namespace smt { return m_plugin->is_shared(n); } - void log_transitive_justification(std::ostream & log, enode *en) { + /** + \brief Ensures that all relevant proof steps to explain why the enode is equal to the root of its + equivalence class are in the log and up-to-date. + */ + void log_justification_to_root(std::ostream & log, enode *en) { enode *root = en->get_root(); for (enode *it = en; it != root; it = it->get_trans_justification().m_target) { if (it->m_proof_logged_status == smt::logged_status::NOT_LOGGED) { it->m_proof_logged_status = smt::logged_status::BEING_LOGGED; - print_justification(log, it); + log_single_justification(log, it); it->m_proof_logged_status = smt::logged_status::LOGGED; } else if (it->m_proof_logged_status != smt::logged_status::BEING_LOGGED && it->get_trans_justification().m_justification.get_kind() == smt::eq_justification::kind::CONGRUENCE) { @@ -119,8 +123,8 @@ namespace smt { enode *target = it->get_trans_justification().m_target; for (unsigned i = 0; i < num_args; ++i) { - log_transitive_justification(log, it->get_arg(i)); - log_transitive_justification(log, target->get_arg(i)); + log_justification_to_root(log, it->get_arg(i)); + log_justification_to_root(log, target->get_arg(i)); } it->m_proof_logged_status = smt::logged_status::LOGGED; } @@ -131,7 +135,11 @@ namespace smt { } } - void print_justification(std::ostream & out, enode *en) { + /** + \brief Logs a single equality explanation step and, if necessary, recursively calls log_justification_to_root to log + equalities needed by the step (e.g. argument equalities for congruence steps). + */ + void log_single_justification(std::ostream & out, enode *en) { smt::literal lit; unsigned num_args; enode *target = en->get_trans_justification().m_target; @@ -149,10 +157,9 @@ namespace smt { if (!en->get_trans_justification().m_justification.used_commutativity()) { num_args = en->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - - log_transitive_justification(out, en->get_arg(i)); - log_transitive_justification(out, target->get_arg(i)); + for (unsigned i = 0; i < num_args; ++i) { + log_justification_to_root(out, en->get_arg(i)); + log_justification_to_root(out, target->get_arg(i)); } out << "[eq-expl] #" << en->get_owner_id() << " cg"; @@ -160,7 +167,7 @@ namespace smt { out << " (#" << en->get_arg(i)->get_owner_id() << " #" << target->get_arg(i)->get_owner_id() << ")"; } out << " ; #" << target->get_owner_id() << "\n"; - + break; } else { out << "[eq-expl] #" << en->get_owner_id() << " nyi ; #" << target->get_owner_id() << "\n"; @@ -172,7 +179,7 @@ namespace smt { symbol const theory = m().get_family_name(th_id); out << "[eq-expl] #" << en->get_owner_id() << " th " << theory.str() << " ; #" << target->get_owner_id() << "\n"; } else { - out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; + out << "[eq-expl] #" << en->get_owner_id() << " unknown ; #" << target->get_owner_id() << "\n"; } break; default: @@ -198,14 +205,14 @@ namespace smt { if (has_trace_stream()) { std::ostream & out = trace_stream(); for (unsigned i = 0; i < num_bindings; ++i) { - log_transitive_justification(out, bindings[i]); + log_justification_to_root(out, bindings[i]); } for (auto n : used_enodes) { enode *orig = std::get<0>(n); enode *substituted = std::get<1>(n); if (orig != nullptr) { - log_transitive_justification(out, orig); - log_transitive_justification(out, substituted); + log_justification_to_root(out, orig); + log_justification_to_root(out, substituted); } } out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); From 1eb8ccad59b8ea2c12b1ec8e7e712c7891b252d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jul 2018 16:04:37 -0700 Subject: [PATCH 007/118] overhaul of error messages. Add warning in dimacs conversion Signed-off-by: Nikolaj Bjorner --- src/api/api_algebraic.cpp | 16 ++-- src/api/api_arith.cpp | 12 +-- src/api/api_array.cpp | 14 ++-- src/api/api_ast.cpp | 54 +++++++------- src/api/api_ast_map.cpp | 2 +- src/api/api_ast_vector.cpp | 7 +- src/api/api_bv.cpp | 7 +- src/api/api_context.cpp | 31 ++++---- src/api/api_context.h | 20 ++--- src/api/api_datalog.cpp | 12 +-- src/api/api_datatype.cpp | 44 +++++------ src/api/api_fpa.cpp | 146 ++++++++++++++++++------------------- src/api/api_goal.cpp | 8 +- src/api/api_model.cpp | 24 +++--- src/api/api_numeral.cpp | 26 +++---- src/api/api_opt.cpp | 6 +- src/api/api_params.cpp | 4 +- src/api/api_parsers.cpp | 23 ++---- src/api/api_polynomial.cpp | 2 +- src/api/api_qe.cpp | 4 +- src/api/api_quant.cpp | 44 +++++------ src/api/api_rcf.cpp | 2 +- src/api/api_seq.cpp | 2 +- src/api/api_solver.cpp | 20 ++--- src/api/api_stats.cpp | 14 ++-- src/api/api_tactic.cpp | 14 ++-- src/api/c++/z3++.h | 2 +- src/api/python/z3/z3.py | 15 +--- src/api/z3_api.h | 11 --- src/tactic/goal.cpp | 21 ++++++ src/tactic/goal.h | 4 +- 31 files changed, 298 insertions(+), 313 deletions(-) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 47d91209e..1bb1b6a51 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -29,14 +29,14 @@ Notes: #define CHECK_IS_ALGEBRAIC(ARG, RET) { \ if (!Z3_algebraic_is_value_core(c, ARG)) { \ - SET_ERROR_CODE(Z3_INVALID_ARG); \ + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); \ return RET; \ } \ } #define CHECK_IS_ALGEBRAIC_X(ARG, RET) { \ if (!Z3_algebraic_is_value_core(c, ARG)) { \ - SET_ERROR_CODE(Z3_INVALID_ARG); \ + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); \ RETURN_Z3(RET); \ } \ } @@ -196,7 +196,7 @@ extern "C" { CHECK_IS_ALGEBRAIC_X(b, nullptr); if ((is_rational(c, b) && get_rational(c, b).is_zero()) || (!is_rational(c, b) && am(c).is_zero(get_irrational(c, b)))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } BIN_OP(/,div); @@ -211,7 +211,7 @@ extern "C" { if (k % 2 == 0) { if ((is_rational(c, a) && get_rational(c, a).is_neg()) || (!is_rational(c, a) && am(c).is_neg(get_irrational(c, a)))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -360,13 +360,13 @@ extern "C" { expr2polynomial converter(mk_c(c)->m(), pm, nullptr, true); if (!converter.to_polynomial(to_expr(p), _p, d) || static_cast(max_var(_p)) >= n + 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } algebraic_numbers::manager & _am = am(c); scoped_anum_vector as(_am); if (!to_anum_vector(c, n, a, as)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } scoped_anum_vector roots(_am); @@ -396,13 +396,13 @@ extern "C" { expr2polynomial converter(mk_c(c)->m(), pm, nullptr, true); if (!converter.to_polynomial(to_expr(p), _p, d) || static_cast(max_var(_p)) >= n) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } algebraic_numbers::manager & _am = am(c); scoped_anum_vector as(_am); if (!to_anum_vector(c, n, a, as)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } { diff --git a/src/api/api_arith.cpp b/src/api/api_arith.cpp index f245dfd18..f46f56ef2 100644 --- a/src/api/api_arith.cpp +++ b/src/api/api_arith.cpp @@ -51,7 +51,7 @@ extern "C" { LOG_Z3_mk_real(c, num, den); RESET_ERROR_CODE(); if (den == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } sort* s = mk_c(c)->m().mk_sort(mk_c(c)->get_arith_fid(), REAL_SORT); @@ -97,7 +97,7 @@ extern "C" { LOG_Z3_mk_sub(c, num_args, args); RESET_ERROR_CODE(); if (num_args == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr* r = to_expr(args[0]); @@ -129,7 +129,7 @@ extern "C" { LOG_Z3_get_algebraic_number_lower(c, a, precision); RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * e = to_expr(a); @@ -147,7 +147,7 @@ extern "C" { LOG_Z3_get_algebraic_number_upper(c, a, precision); RESET_ERROR_CODE(); if (!Z3_is_algebraic_number(c, a)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * e = to_expr(a); @@ -167,7 +167,7 @@ extern "C" { rational val; ast * _a = to_ast(a); if (!is_expr(_a) || !mk_c(c)->autil().is_numeral(to_expr(_a), val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(numerator(val), true); @@ -183,7 +183,7 @@ extern "C" { rational val; ast * _a = to_ast(a); if (!is_expr(_a) || !mk_c(c)->autil().is_numeral(to_expr(_a), val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } expr * r = mk_c(c)->autil().mk_numeral(denominator(val), true); diff --git a/src/api/api_array.cpp b/src/api/api_array.cpp index 31391e218..a9f5d7d70 100644 --- a/src/api/api_array.cpp +++ b/src/api/api_array.cpp @@ -58,7 +58,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } sort * domain[2] = {a_ty, i_ty}; @@ -81,7 +81,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); // sort * i_ty = m.get_sort(_i); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } ptr_vector domain; @@ -113,7 +113,7 @@ extern "C" { sort * i_ty = m.get_sort(_i); sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } sort * domain[3] = {a_ty, i_ty, v_ty}; @@ -136,7 +136,7 @@ extern "C" { sort * a_ty = m.get_sort(_a); sort * v_ty = m.get_sort(_v); if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } ptr_vector domain; @@ -163,7 +163,7 @@ extern "C" { LOG_Z3_mk_map(c, f, n, args); RESET_ERROR_CODE(); if (n == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ast_manager & m = mk_c(c)->m(); @@ -298,7 +298,7 @@ extern "C" { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(0).get_ast()); RETURN_Z3(r); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); Z3_CATCH_RETURN(nullptr); } @@ -314,7 +314,7 @@ extern "C" { Z3_sort r = reinterpret_cast(to_sort(t)->get_parameter(n-1).get_ast()); RETURN_Z3(r); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 0753d3ffe..5828b0fcd 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -48,7 +48,7 @@ extern "C" { LOG_Z3_mk_int_symbol(c, i); RESET_ERROR_CODE(); if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } Z3_symbol result = of_symbol(symbol(i)); @@ -281,7 +281,7 @@ extern "C" { if (_s.is_numerical()) { return _s.get_num(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return -1; Z3_CATCH_RETURN(-1); } @@ -355,7 +355,7 @@ extern "C" { LOG_Z3_get_app_decl(c, a); RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_app(a)->get_decl())); @@ -371,11 +371,11 @@ extern "C" { LOG_Z3_get_app_arg(c, a, i); RESET_ERROR_CODE(); if (!is_app(reinterpret_cast(a))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } if (i >= to_app(a)->get_num_args()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_ast(to_app(a)->get_arg(i))); @@ -398,7 +398,7 @@ extern "C" { LOG_Z3_get_decl_parameter_kind(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_PARAMETER_INT; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; @@ -430,12 +430,12 @@ extern "C" { LOG_Z3_get_decl_int_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_int()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return p.get_int(); @@ -447,12 +447,12 @@ extern "C" { LOG_Z3_get_decl_double_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_double()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return p.get_double(); @@ -464,12 +464,12 @@ extern "C" { LOG_Z3_get_decl_symbol_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_symbol()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } return of_symbol(p.get_symbol()); @@ -481,12 +481,12 @@ extern "C" { LOG_Z3_get_decl_sort_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast() || !is_sort(p.get_ast())) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_sort(to_sort(p.get_ast()))); @@ -498,12 +498,12 @@ extern "C" { LOG_Z3_get_decl_ast_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_ast(p.get_ast())); @@ -515,12 +515,12 @@ extern "C" { LOG_Z3_get_decl_func_decl_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_ast() || !is_func_decl(p.get_ast())) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(of_func_decl(to_func_decl(p.get_ast()))); @@ -532,12 +532,12 @@ extern "C" { LOG_Z3_get_decl_rational_parameter(c, d, idx); RESET_ERROR_CODE(); if (idx >= to_func_decl(d)->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } parameter const& p = to_func_decl(d)->get_parameters()[idx]; if (!p.is_rational()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return mk_c(c)->mk_external_string(p.get_rational().to_string()); @@ -584,7 +584,7 @@ extern "C" { LOG_Z3_get_domain(c, d, i); RESET_ERROR_CODE(); if (i >= to_func_decl(d)->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_sort r = of_sort(to_func_decl(d)->get_domain(i)); @@ -740,7 +740,7 @@ extern "C" { case AST_APP: { app* e = to_app(a); if (e->get_num_args() != num_args) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); } else { a = m.mk_app(e->get_decl(), num_args, args); @@ -749,7 +749,7 @@ extern "C" { } case AST_QUANTIFIER: { if (num_args != 1) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); } else { a = m.update_quantifier(to_quantifier(a), args[0]); @@ -779,7 +779,7 @@ extern "C" { expr * r = nullptr; for (unsigned i = 0; i < num_exprs; i++) { if (m.get_sort(from[i]) != m.get_sort(to[i])) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(of_expr(nullptr)); } SASSERT(from[i]->get_ref_count() > 0); @@ -1212,14 +1212,14 @@ extern "C" { RESET_ERROR_CODE(); ast* _a = reinterpret_cast(a); if (!_a || _a->get_kind() != AST_VAR) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } var* va = to_var(_a); if (va) { return va->get_idx(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; Z3_CATCH_RETURN(0); } @@ -1230,7 +1230,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(a, nullptr); if (c == target) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } SASSERT(mk_c(c)->m().contains(to_ast(a))); diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 17dd086b5..44cadc691 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -71,7 +71,7 @@ extern "C" { RESET_ERROR_CODE(); obj_map::obj_map_entry * entry = to_ast_map_ref(m).find_core(to_ast(k)); if (entry == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } else { diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index ae5adecea..5fe19a7d5 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -65,7 +65,7 @@ extern "C" { LOG_Z3_ast_vector_get(c, v, i); RESET_ERROR_CODE(); if (i >= to_ast_vector_ref(v).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } // Remark: Don't need to invoke save_object. @@ -79,7 +79,7 @@ extern "C" { LOG_Z3_ast_vector_set(c, v, i, a); RESET_ERROR_CODE(); if (i >= to_ast_vector_ref(v).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } to_ast_vector_ref(v).set(i, to_ast(a)); @@ -107,8 +107,7 @@ extern "C" { LOG_Z3_ast_vector_translate(c, v, t); RESET_ERROR_CODE(); if (c == t) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(nullptr); + RETURN_Z3(v); } ast_translation translator(mk_c(c)->m(), mk_c(t)->m()); Z3_ast_vector_ref * new_v = alloc(Z3_ast_vector_ref, *mk_c(t), mk_c(t)->m()); diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 1876d930d..bd603aa6d 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -27,9 +27,6 @@ extern "C" { Z3_TRY; LOG_Z3_mk_bv_sort(c, sz); RESET_ERROR_CODE(); - if (sz == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); - } parameter p(sz); Z3_sort r = of_sort(mk_c(c)->m().mk_sort(mk_c(c)->get_bv_fid(), BV_SORT, 1, &p)); RETURN_Z3(r); @@ -163,7 +160,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ // Not logging this one, since it is just syntax sugar. unsigned sz = Z3_get_bv_sort_size(c, s); if (sz == 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "zero length bit-vector supplied"); return nullptr; } Z3_ast x = Z3_mk_int64(c, 1, s); @@ -393,7 +390,7 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ if (to_sort(t)->get_family_id() == mk_c(c)->get_bv_fid() && to_sort(t)->get_decl_kind() == BV_SORT) { return to_sort(t)->get_parameter(0).get_int(); } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort is not a bit-vector"); return 0; Z3_CATCH_RETURN(0); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 295977a06..673d0b1c9 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -144,9 +144,11 @@ namespace api { } } - void context::set_error_code(Z3_error_code err) { + void context::set_error_code(Z3_error_code err, char const* opt_msg) { m_error_code = err; if (err != Z3_OK) { + m_exception_msg.clear(); + if (opt_msg) m_exception_msg = opt_msg; invoke_error_handler(err); } } @@ -159,7 +161,7 @@ namespace api { void context::check_searching() { if (m_searching) { - set_error_code(Z3_INVALID_USAGE); // TBD: error code could be fixed. + set_error_code(Z3_INVALID_USAGE, "cannot use function while searching"); // TBD: error code could be fixed. } } @@ -248,25 +250,24 @@ namespace api { if (ex.has_error_code()) { switch(ex.error_code()) { case ERR_MEMOUT: - set_error_code(Z3_MEMOUT_FAIL); + set_error_code(Z3_MEMOUT_FAIL, nullptr); break; case ERR_PARSER: - set_error_code(Z3_PARSER_ERROR); + set_error_code(Z3_PARSER_ERROR, ex.msg()); break; case ERR_INI_FILE: - set_error_code(Z3_INVALID_ARG); + set_error_code(Z3_INVALID_ARG, nullptr); break; case ERR_OPEN_FILE: - set_error_code(Z3_FILE_ACCESS_ERROR); + set_error_code(Z3_FILE_ACCESS_ERROR, nullptr); break; default: - set_error_code(Z3_INTERNAL_FATAL); + set_error_code(Z3_INTERNAL_FATAL, nullptr); break; } } else { - m_exception_msg = ex.msg(); - set_error_code(Z3_EXCEPTION); + set_error_code(Z3_EXCEPTION, ex.msg()); } } @@ -301,7 +302,7 @@ namespace api { case AST_FUNC_DECL: break; } - set_error_code(Z3_SORT_ERROR); + set_error_code(Z3_SORT_ERROR, nullptr); } } @@ -379,7 +380,7 @@ extern "C" { LOG_Z3_dec_ref(c, a); RESET_ERROR_CODE(); if (to_ast(a)->get_ref_count() == 0) { - SET_ERROR_CODE(Z3_DEC_REF_ERROR); + SET_ERROR_CODE(Z3_DEC_REF_ERROR, nullptr); return; } mk_c(c)->m().dec_ref(to_ast(a)); @@ -440,10 +441,14 @@ extern "C" { } void Z3_API Z3_set_error(Z3_context c, Z3_error_code e) { - SET_ERROR_CODE(e); + SET_ERROR_CODE(e, nullptr); } static char const * _get_error_msg(Z3_context c, Z3_error_code err) { + if (c) { + char const* msg = mk_c(c)->get_exception_msg(); + if (msg && *msg) return msg; + } switch(err) { case Z3_OK: return "ok"; case Z3_SORT_ERROR: return "type error"; @@ -457,7 +462,7 @@ extern "C" { case Z3_INTERNAL_FATAL: return "internal error"; case Z3_INVALID_USAGE: return "invalid usage"; case Z3_DEC_REF_ERROR: return "invalid dec_ref command"; - case Z3_EXCEPTION: return c == nullptr ? "Z3 exception" : mk_c(c)->get_exception_msg(); + case Z3_EXCEPTION: return "Z3 exception"; default: return "unknown"; } } diff --git a/src/api/api_context.h b/src/api/api_context.h index 50e89113d..a6f55d1aa 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -141,7 +141,7 @@ namespace api { Z3_error_code get_error_code() const { return m_error_code; } void reset_error_code(); - void set_error_code(Z3_error_code err); + void set_error_code(Z3_error_code err, char const* opt_msg); void set_error_handler(Z3_error_handler h) { m_error_handler = h; } // Sign an error if solver is searching void check_searching(); @@ -219,14 +219,6 @@ namespace api { // // ------------------------ smt_params & fparams() { return m_fparams; } - - // ------------------------ - // - // Parser interface - // - // ------------------------ - - std::string m_parser_error_buffer; }; @@ -234,14 +226,14 @@ namespace api { inline api::context * mk_c(Z3_context c) { return reinterpret_cast(c); } #define RESET_ERROR_CODE() { mk_c(c)->reset_error_code(); } -#define SET_ERROR_CODE(ERR) { mk_c(c)->set_error_code(ERR); } -#define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == 0) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } -#define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define SET_ERROR_CODE(ERR, MSG) { mk_c(c)->set_error_code(ERR, MSG); } +#define CHECK_NON_NULL(_p_,_ret_) { if (_p_ == 0) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is null"); return _ret_; } } +#define CHECK_VALID_AST(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "not a valid ast"); return _ret_; } } #define CHECK_SEARCHING(c) mk_c(c)->check_searching(); inline bool is_expr(Z3_ast a) { return is_expr(to_ast(a)); } -#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define CHECK_IS_EXPR(_p_, _ret_) { if (_p_ == 0 || !is_expr(_p_)) { SET_ERROR_CODE(Z3_INVALID_ARG, "ast is not an expression"); return _ret_; } } inline bool is_bool_expr(Z3_context c, Z3_ast a) { return is_expr(a) && mk_c(c)->m().is_bool(to_expr(a)); } -#define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG); return _ret_; } } +#define CHECK_FORMULA(_a_, _ret_) { if (_a_ == 0 || !CHECK_REF_COUNT(_a_) || !is_bool_expr(c, _a_)) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return _ret_; } } inline void check_sorts(Z3_context c, ast * n) { mk_c(c)->check_sorts(n); } #endif diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index fd31a65f8..b0a4def55 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -157,7 +157,7 @@ extern "C" { RESET_ERROR_CODE(); sort * r = to_sort(s); if (Z3_get_sort_kind(c, s) != Z3_RELATION_SORT) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort should be a relation"); return 0; } return r->get_num_parameters(); @@ -170,18 +170,18 @@ extern "C" { RESET_ERROR_CODE(); sort * r = to_sort(s); if (Z3_get_sort_kind(c, s) != Z3_RELATION_SORT) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sort should be a relation"); RETURN_Z3(nullptr); } if (col >= r->get_num_parameters()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } parameter const& p = r->get_parameter(col); if (!p.is_ast() || !is_sort(p.get_ast())) { UNREACHABLE(); warning_msg("Sort parameter expected at %d", col); - SET_ERROR_CODE(Z3_INTERNAL_FATAL); + SET_ERROR_CODE(Z3_INTERNAL_FATAL, "sort parameter expected"); RETURN_Z3(nullptr); } Z3_sort res = of_sort(to_sort(p.get_ast())); @@ -364,7 +364,7 @@ extern "C" { install_dl_collect_cmds(coll, ctx); ctx.set_ignore_check(true); if (!parse_smt2_commands(ctx, s)) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); return nullptr; } @@ -408,7 +408,7 @@ extern "C" { LOG_Z3_fixedpoint_from_file(c, d, s); std::ifstream is(s); if (!is) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); RETURN_Z3(nullptr); } RETURN_Z3(Z3_fixedpoint_from_stream(c, d, is)); diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 799e537ea..0c2544643 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -56,7 +56,7 @@ extern "C" { del_datatype_decl(dt); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -118,7 +118,7 @@ extern "C" { del_datatype_decl(dt); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -180,7 +180,7 @@ extern "C" { del_datatype_decl(decl); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -274,7 +274,7 @@ extern "C" { RESET_ERROR_CODE(); mk_c(c)->reset_last_result(); if (!constr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } ast_manager& m = mk_c(c)->m(); @@ -282,7 +282,7 @@ extern "C" { func_decl* f = reinterpret_cast(constr)->m_constructor.get(); if (!f) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } if (constructor_decl) { @@ -353,7 +353,7 @@ extern "C" { del_datatype_decl(data); if (!is_ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -416,7 +416,7 @@ extern "C" { del_datatype_decls(datas.size(), datas.c_ptr()); if (!ok) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return; } @@ -445,7 +445,7 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return dt_util.get_datatype_constructors(_t)->size(); @@ -458,12 +458,12 @@ extern "C" { sort * _t = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } func_decl* decl = (decls)[idx]; @@ -488,12 +488,12 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } func_decl* decl = (decls)[idx]; @@ -511,23 +511,23 @@ extern "C" { datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(_t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(_t); if (idx_c >= decls.size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } func_decl* decl = (decls)[idx_c]; if (decl->get_arity() <= idx_a) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & accs = *dt_util.get_constructor_accessors(decl); SASSERT(accs.size() == decl->get_arity()); if (accs.size() <= idx_a) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } decl = (accs)[idx_a]; @@ -543,7 +543,7 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_func_decl r = get_datatype_sort_constructor_core(c, t, 0); @@ -558,12 +558,12 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } ptr_vector const & accs = *dt_util.get_constructor_accessors(decls[0]); @@ -578,17 +578,17 @@ extern "C" { sort * tuple = to_sort(t); datatype_util& dt_util = mk_c(c)->dtutil(); if (!dt_util.is_datatype(tuple) || dt_util.is_recursive(tuple) || dt_util.get_datatype_num_constructors(tuple) != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & accs = *dt_util.get_constructor_accessors((decls)[0]); if (accs.size() <= i) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } func_decl* acc = (accs)[i]; diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 261198354..cdc592527 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -175,7 +175,7 @@ extern "C" { LOG_Z3_mk_fpa_sort(c, ebits, sbits); RESET_ERROR_CODE(); if (ebits < 2 || sbits < 3) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "ebits should be at least 2, sbits at least 3"); } api::context * ctx = mk_c(c); sort * s = ctx->fpautil().mk_float_sort(ebits, sbits); @@ -222,7 +222,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -238,7 +238,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -255,7 +255,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_VALID_AST(s, nullptr); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -271,7 +271,7 @@ extern "C" { LOG_Z3_mk_fpa_fp(c, sgn, exp, sig); RESET_ERROR_CODE(); if (!is_bv(c, sgn) || !is_bv(c, exp) || !is_bv(c, sig)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv sorts expected for arguments"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -286,7 +286,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_float(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG,"fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -306,7 +306,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_double(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -323,7 +323,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int(c, v, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -343,7 +343,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -363,7 +363,7 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int64_uint64(c, sgn, exp, sig, ty); RESET_ERROR_CODE(); if (!is_fp_sort(c, ty)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -383,7 +383,7 @@ extern "C" { LOG_Z3_mk_fpa_abs(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -398,7 +398,7 @@ extern "C" { LOG_Z3_mk_fpa_neg(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -413,7 +413,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -428,7 +428,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -443,7 +443,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -458,7 +458,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -473,7 +473,7 @@ extern "C" { LOG_Z3_mk_fpa_fma(c, rm, t1, t2, t3); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t1) || !is_fp(c, t2) || !is_fp(c, t3)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -488,7 +488,7 @@ extern "C" { LOG_Z3_mk_fpa_sqrt(c, rm, t); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -503,7 +503,7 @@ extern "C" { LOG_Z3_mk_fpa_rem(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -518,7 +518,7 @@ extern "C" { LOG_Z3_mk_fpa_round_to_integral(c, rm, t); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -533,7 +533,7 @@ extern "C" { LOG_Z3_mk_fpa_min(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -548,7 +548,7 @@ extern "C" { LOG_Z3_mk_fpa_max(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -563,7 +563,7 @@ extern "C" { LOG_Z3_mk_fpa_leq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -578,7 +578,7 @@ extern "C" { LOG_Z3_mk_fpa_lt(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -593,7 +593,7 @@ extern "C" { LOG_Z3_mk_fpa_geq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -608,7 +608,7 @@ extern "C" { LOG_Z3_mk_fpa_gt(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -623,7 +623,7 @@ extern "C" { LOG_Z3_mk_fpa_eq(c, t1, t2); RESET_ERROR_CODE(); if (!is_fp(c, t1) || !is_fp(c, t2)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -638,7 +638,7 @@ extern "C" { LOG_Z3_mk_fpa_is_normal(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -653,7 +653,7 @@ extern "C" { LOG_Z3_mk_fpa_is_subnormal(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -668,7 +668,7 @@ extern "C" { LOG_Z3_mk_fpa_is_zero(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -683,7 +683,7 @@ extern "C" { LOG_Z3_mk_fpa_is_infinite(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -698,7 +698,7 @@ extern "C" { LOG_Z3_mk_fpa_is_nan(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -713,7 +713,7 @@ extern "C" { LOG_Z3_mk_fpa_is_negative(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -728,7 +728,7 @@ extern "C" { LOG_Z3_mk_fpa_is_positive(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -744,14 +744,14 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_bv(c, bv, s); RESET_ERROR_CODE(); if (!is_bv(c, bv) || !is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv then fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!ctx->bvutil().is_bv(to_expr(bv)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "bv sort the flaot sort expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(bv)); @@ -769,7 +769,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !fu.is_float(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -787,7 +787,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->autil().is_real(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -805,7 +805,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)); @@ -823,7 +823,7 @@ extern "C" { if (!fu.is_rm(to_expr(rm)) || !ctx->bvutil().is_bv(to_expr(t)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); return nullptr; } expr * a = fu.mk_to_fp_unsigned(to_sort(s), to_expr(rm), to_expr(t)); @@ -837,7 +837,7 @@ extern "C" { LOG_Z3_mk_fpa_to_ubv(c, rm, t, sz); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -852,7 +852,7 @@ extern "C" { LOG_Z3_mk_fpa_to_sbv(c, rm, t, sz); RESET_ERROR_CODE(); if (!is_rm(c, rm) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "rm and float sorts expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -867,7 +867,7 @@ extern "C" { LOG_Z3_mk_fpa_to_real(c, t); RESET_ERROR_CODE(); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -884,7 +884,7 @@ extern "C" { CHECK_NON_NULL(s, 0); CHECK_VALID_AST(s, 0); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(0); } return mk_c(c)->fpautil().get_ebits(to_sort(s)); @@ -898,7 +898,7 @@ extern "C" { CHECK_NON_NULL(s, 0); CHECK_VALID_AST(s, 0); if (!is_fp_sort(c, s)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(0); } return mk_c(c)->fpautil().get_sbits(to_sort(s)); @@ -912,7 +912,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (sgn == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "sign cannot be a nullpointer"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -921,13 +921,13 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return 0; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(to_expr(t), val); if (!r || mpfm.is_nan(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return 0; } *sgn = mpfm.sgn(val); @@ -948,13 +948,13 @@ extern "C" { api::context * ctx = mk_c(c); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(to_expr(t), val); if (!r || mpfm.is_nan(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return nullptr; } app * a; @@ -981,13 +981,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } unsigned sbits = val.get().get_sbits(); @@ -1014,13 +1014,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } unsigned sbits = val.get().get_sbits(); @@ -1042,7 +1042,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (n == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid nullptr argument"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -1053,7 +1053,7 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1063,7 +1063,7 @@ extern "C" { if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val)) || !mpzm.is_uint64(z)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1085,13 +1085,13 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); return ""; } unsigned ebits = val.get().get_ebits(); @@ -1120,7 +1120,7 @@ extern "C" { CHECK_NON_NULL(t, 0); CHECK_VALID_AST(t, 0); if (n == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid null argument"); return 0; } ast_manager & m = mk_c(c)->m(); @@ -1130,14 +1130,14 @@ extern "C" { SASSERT(plugin != 0); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); *n = 0; return 0; } @@ -1169,13 +1169,13 @@ extern "C" { fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); expr * e = to_expr(t); if (!is_app(e) || is_app_of(e, fid, OP_FPA_NAN) || !is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } scoped_mpf val(mpfm); bool r = plugin->is_numeral(e, val); if (!r || !(mpfm.is_normal(val) || mpfm.is_denormal(val) || mpfm.is_zero(val) || mpfm.is_inf(val))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "invalid expression argument, expecting a valid fp, not a NaN"); RETURN_Z3(nullptr); } unsigned ebits = val.get().get_ebits(); @@ -1204,7 +1204,7 @@ extern "C" { CHECK_NON_NULL(t, nullptr); CHECK_VALID_AST(t, nullptr); if (!is_fp(c, t)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "fp sort expected"); RETURN_Z3(nullptr); } api::context * ctx = mk_c(c); @@ -1223,7 +1223,7 @@ extern "C" { !ctx->autil().is_int(to_expr(exp)) || !ctx->autil().is_real(to_expr(sig)) || !fu.is_float(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(exp), to_expr(sig)); @@ -1239,7 +1239,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_nan(to_expr(t)); @@ -1253,7 +1253,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_inf(to_expr(t)); @@ -1267,7 +1267,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_zero(to_expr(t)); @@ -1281,7 +1281,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_normal(to_expr(t)); @@ -1295,7 +1295,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_subnormal(to_expr(t)); @@ -1309,7 +1309,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_positive(to_expr(t)); @@ -1323,7 +1323,7 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!is_expr(t) || !fu.is_numeral(to_expr(t))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return fu.is_negative(to_expr(t)); diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index ae48a3f6f..090553df5 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -30,7 +30,7 @@ extern "C" { LOG_Z3_mk_goal(c, models, unsat_cores, proofs); RESET_ERROR_CODE(); if (proofs != 0 && !mk_c(c)->m().proofs_enabled()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "proofs are required, but proofs are not enabled on the context"); RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); @@ -119,7 +119,7 @@ extern "C" { LOG_Z3_goal_formula(c, g, idx); RESET_ERROR_CODE(); if (idx >= to_goal_ref(g)->size()) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } expr * result = to_goal_ref(g)->form(idx); @@ -198,6 +198,10 @@ extern "C" { LOG_Z3_goal_to_dimacs_string(c, g); RESET_ERROR_CODE(); std::ostringstream buffer; + if (!to_goal_ref(g)->is_cnf()) { + warning_msg("goal is not in CNF. This will produce a propositional abstraction. " + "If this is not what you want, then preprocess by optional bit-blasting and applying tseitin-cnf"); + } to_goal_ref(g)->display_dimacs(buffer); // Hack for removing the trailing '\n' std::string result = buffer.str(); diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 7eb7d2fdd..e9dd3580b 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -94,7 +94,7 @@ extern "C" { CHECK_NON_NULL(m, nullptr); func_interp * _fi = to_model_ref(m)->get_func_interp(to_func_decl(f)); if (!_fi) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_func_interp_ref * fi = alloc(Z3_func_interp_ref, *mk_c(c), to_model_ref(m)); @@ -123,7 +123,7 @@ extern "C" { RETURN_Z3(of_func_decl(_m->get_constant(i))); } else { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -142,7 +142,7 @@ extern "C" { CHECK_NON_NULL(m, nullptr); model * _m = to_model_ref(m); if (i >= _m->get_num_functions()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return nullptr; } return of_func_decl(_m->get_function(i)); @@ -187,7 +187,7 @@ extern "C" { LOG_Z3_model_get_sort(c, m, i); RESET_ERROR_CODE(); if (i >= to_model_ref(m)->get_num_uninterpreted_sorts()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } sort * s = to_model_ref(m)->get_uninterpreted_sort(i); @@ -200,7 +200,7 @@ extern "C" { LOG_Z3_model_get_sort_universe(c, m, s); RESET_ERROR_CODE(); if (!to_model_ref(m)->has_uninterpreted_sort(to_sort(s))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } ptr_vector const & universe = to_model_ref(m)->get_universe(to_sort(s)); @@ -242,7 +242,7 @@ extern "C" { RETURN_Z3(of_func_decl(to_func_decl(to_app(a)->get_decl()->get_parameter(0).get_ast()))); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -269,7 +269,7 @@ extern "C" { RESET_ERROR_CODE(); func_decl* d = to_func_decl(f); if (d->get_arity() != 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); } else { model* mdl = to_model_ref(m); @@ -313,7 +313,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(f, nullptr); if (i >= to_func_interp_ref(f)->num_entries()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_func_entry_ref * e = alloc(Z3_func_entry_ref, *mk_c(c), to_func_interp(f)->m_model.get()); @@ -364,7 +364,7 @@ extern "C" { func_interp* _fi = to_func_interp_ref(fi); expr* _value = to_expr(value); if (to_ast_vector_ref(args).size() != _fi->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } // check sorts of value @@ -416,7 +416,7 @@ extern "C" { LOG_Z3_func_entry_get_arg(c, e, i); RESET_ERROR_CODE(); if (i >= to_func_entry(e)->m_func_interp->get_arity()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } expr * r = to_func_entry(e)->m_func_entry->get_arg(i); @@ -434,7 +434,7 @@ extern "C" { if (g) { return g->num_entries(); } - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } return 0; @@ -448,7 +448,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(m, 0); if (j >= get_model_func_num_entries_core(c, m, i)) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } Z3_func_decl d = get_model_func_decl_core(c, m, i); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index de9886571..b5458cff2 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -40,7 +40,7 @@ bool is_numeral_sort(Z3_context c, Z3_sort ty) { bool check_numeral_sort(Z3_context c, Z3_sort ty) { bool is_num = is_numeral_sort(c, ty); if (!is_num) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); } return is_num; } @@ -55,7 +55,7 @@ extern "C" { RETURN_Z3(nullptr); } if (!n) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } sort * _ty = to_sort(ty); @@ -72,7 +72,7 @@ extern "C" { (('p' == *m) || ('P' == *m) || ('+' == *m))))) { - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); RETURN_Z3(nullptr); } ++m; @@ -162,7 +162,7 @@ extern "C" { RESET_ERROR_CODE(); expr* e = to_expr(a); if (!e) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } if (mk_c(c)->autil().is_numeral(e, r)) { @@ -221,7 +221,7 @@ extern "C" { return mk_c(c)->mk_external_string(fu.fm().to_string(tmp)); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } } @@ -234,7 +234,7 @@ extern "C" { RESET_ERROR_CODE(); expr* e = to_expr(a); if (!e) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } rational r; @@ -256,7 +256,7 @@ extern "C" { return mk_c(c)->mk_external_string(r.to_string()); } else { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } Z3_CATCH_RETURN(""); @@ -281,7 +281,7 @@ extern "C" { return Z3_FALSE; } } - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } @@ -293,7 +293,7 @@ extern "C" { LOG_Z3_get_numeral_int(c, v, i); RESET_ERROR_CODE(); if (!i) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } int64_t l; @@ -311,7 +311,7 @@ extern "C" { LOG_Z3_get_numeral_uint(c, v, u); RESET_ERROR_CODE(); if (!u) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } uint64_t l; @@ -329,7 +329,7 @@ extern "C" { LOG_Z3_get_numeral_uint64(c, v, u); RESET_ERROR_CODE(); if (!u) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; @@ -349,7 +349,7 @@ extern "C" { LOG_Z3_get_numeral_int64(c, v, i); RESET_ERROR_CODE(); if (!i) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; @@ -368,7 +368,7 @@ extern "C" { LOG_Z3_get_numeral_rational_int64(c, v, num, den); RESET_ERROR_CODE(); if (!num || !den) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return Z3_FALSE; } rational r; diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 4bb146e39..71f92eeba 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -318,17 +318,15 @@ extern "C" { ctx->set_ignore_check(true); try { if (!parse_smt2_commands(*ctx.get(), s)) { - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } } catch (z3_exception& e) { errstrm << e.msg(); - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } diff --git a/src/api/api_params.cpp b/src/api/api_params.cpp index d021ed6ad..9d9f5157c 100644 --- a/src/api/api_params.cpp +++ b/src/api/api_params.cpp @@ -171,7 +171,7 @@ extern "C" { LOG_Z3_param_descrs_get_name(c, p, i); RESET_ERROR_CODE(); if (i >= to_param_descrs_ptr(p)->size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_symbol result = of_symbol(to_param_descrs_ptr(p)->get_param_name(i)); @@ -185,7 +185,7 @@ extern "C" { RESET_ERROR_CODE(); char const* result = to_param_descrs_ptr(p)->get_descr(to_symbol(s)); if (result == nullptr) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } return mk_c(c)->mk_external_string(result); diff --git a/src/api/api_parsers.cpp b/src/api/api_parsers.cpp index d791dc2a5..b88f273f9 100644 --- a/src/api/api_parsers.cpp +++ b/src/api/api_parsers.cpp @@ -30,15 +30,6 @@ Revision History: extern "C" { - - Z3_string Z3_API Z3_get_parser_error(Z3_context c) { - Z3_TRY; - LOG_Z3_get_parser_error(c); - RESET_ERROR_CODE(); - return mk_c(c)->m_parser_error_buffer.c_str(); - Z3_CATCH_RETURN(""); - } - // --------------- // Support for SMTLIB2 @@ -70,16 +61,14 @@ extern "C" { try { if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; - mk_c(c)->m_parser_error_buffer = errstrm.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return of_ast_vector(v); } } catch (z3_exception& e) { errstrm << e.msg(); - mk_c(c)->m_parser_error_buffer = errstrm.str(); ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return of_ast_vector(v); } ptr_vector::const_iterator it = ctx->begin_assertions(); @@ -118,7 +107,7 @@ extern "C" { LOG_Z3_parse_smtlib2_string(c, file_name, num_sorts, sort_names, sorts, num_decls, decl_names, decls); std::ifstream is(file_name); if (!is) { - SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); return nullptr; } Z3_ast_vector r = parse_smtlib2_stream(false, c, is, num_sorts, sort_names, sorts, num_decls, decl_names, decls); @@ -141,15 +130,13 @@ extern "C" { ctx->set_diagnostic_stream(ous); try { if (!parse_smt2_commands(*ctx.get(), is)) { - mk_c(c)->m_parser_error_buffer = ous.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, ous.str().c_str()); RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } } catch (z3_exception& e) { if (ous.str().empty()) ous << e.msg(); - mk_c(c)->m_parser_error_buffer = ous.str(); - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, ous.str().c_str()); RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); } RETURN_Z3(mk_c(c)->mk_external_string(ous.str())); diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 35ece4a59..8c5fc99c9 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -49,7 +49,7 @@ extern "C" { default_expr2polynomial converter(mk_c(c)->m(), pm); if (!converter.to_polynomial(to_expr(p), _p, d) || !converter.to_polynomial(to_expr(q), _q, d)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return nullptr; } Z3_ast_vector_ref* result = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); diff --git a/src/api/api_qe.cpp b/src/api/api_qe.cpp index 92517b02b..94e83144f 100644 --- a/src/api/api_qe.cpp +++ b/src/api/api_qe.cpp @@ -55,7 +55,7 @@ extern "C" app_ref_vector vars(mk_c(c)->m ()); if (!to_apps(num_bounds, bound, vars)) { - SET_ERROR_CODE (Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } @@ -141,7 +141,7 @@ extern "C" for (unsigned i = 0; i < vVars.size (); ++i) { app *a = to_app (vVars.get (i)); if (a->get_kind () != AST_APP) { - SET_ERROR_CODE (Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } vApps.push_back (a); diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index b760760a4..6d6d19d56 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -62,11 +62,11 @@ extern "C" { Z3_TRY; RESET_ERROR_CODE(); if (!mk_c(c)->m().is_bool(to_expr(body))) { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return nullptr; } if (num_patterns > 0 && num_no_patterns > 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); return nullptr; } expr * const* ps = reinterpret_cast(patterns); @@ -77,7 +77,7 @@ extern "C" { pattern_validator v(mk_c(c)->m()); for (unsigned i = 0; i < num_patterns; i++) { if (!v(num_decls, ps[i], 0, 0)) { - SET_ERROR_CODE(Z3_INVALID_PATTERN); + SET_ERROR_CODE(Z3_INVALID_PATTERN, nullptr); return nullptr; } } @@ -154,7 +154,7 @@ extern "C" { RESET_ERROR_CODE(); expr_ref result(mk_c(c)->m()); if (num_decls == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(0); } @@ -177,7 +177,7 @@ extern "C" { LOG_Z3_mk_lambda_const(c, num_decls, vars, body); RESET_ERROR_CODE(); if (num_decls == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(0); } @@ -220,17 +220,17 @@ extern "C" { svector types; ptr_vector bound_asts; if (num_patterns > 0 && num_no_patterns > 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, nullptr); RETURN_Z3(nullptr); } if (num_bound == 0) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "number of bound variables is 0"); RETURN_Z3(nullptr); } for (unsigned i = 0; i < num_bound; ++i) { app* a = to_app(bound[i]); if (a->get_kind() != AST_APP) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } symbol s(to_app(a)->get_decl()->get_name()); @@ -238,7 +238,7 @@ extern "C" { types.push_back(of_sort(mk_c(c)->m().get_sort(a))); bound_asts.push_back(a); if (a->get_family_id() != null_family_id || a->get_num_args() != 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -259,7 +259,7 @@ extern "C" { for (unsigned i = 0; i < num_no_patterns; ++i) { expr_ref result(mk_c(c)->m()); if (!is_app(to_expr(no_patterns[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } app* pat = to_app(to_expr(no_patterns[i])); @@ -323,7 +323,7 @@ extern "C" { RESET_ERROR_CODE(); for (unsigned i = 0; i < num_patterns; ++i) { if (!is_app(to_expr(terms[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } } @@ -377,7 +377,7 @@ extern "C" { return to_quantifier(_a)->get_weight(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -392,7 +392,7 @@ extern "C" { return to_quantifier(_a)->get_num_patterns(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -408,7 +408,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -424,7 +424,7 @@ extern "C" { return to_quantifier(_a)->get_num_no_patterns(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -440,7 +440,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -455,7 +455,7 @@ extern "C" { return of_symbol(to_quantifier(_a)->get_decl_names()[i]); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return nullptr; } Z3_CATCH_RETURN(nullptr); @@ -471,7 +471,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -487,7 +487,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); @@ -503,7 +503,7 @@ extern "C" { return to_quantifier(_a)->get_num_decls(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -518,7 +518,7 @@ extern "C" { return _p->get_num_args(); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); return 0; } Z3_CATCH_RETURN(0); @@ -534,7 +534,7 @@ extern "C" { RETURN_Z3(r); } else { - SET_ERROR_CODE(Z3_SORT_ERROR); + SET_ERROR_CODE(Z3_SORT_ERROR, nullptr); RETURN_Z3(nullptr); } Z3_CATCH_RETURN(nullptr); diff --git a/src/api/api_rcf.cpp b/src/api/api_rcf.cpp index 3d65cb1cd..d92ff155b 100644 --- a/src/api/api_rcf.cpp +++ b/src/api/api_rcf.cpp @@ -123,7 +123,7 @@ extern "C" { } if (rz == 0) { // it is the zero polynomial - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } av.shrink(rz); diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 84cfdca32..42979d1ed 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -107,7 +107,7 @@ extern "C" { RESET_ERROR_CODE(); zstring str; if (!mk_c(c)->sutil().str.is_string(to_expr(s), str)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "expression is not a string literal"); return ""; } std::string result = str.encode(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 1c8d205bc..9ad51aaf4 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -145,10 +145,12 @@ extern "C" { void solver_from_stream(Z3_context c, Z3_solver s, std::istream& is) { scoped_ptr ctx = alloc(cmd_context, false, &(mk_c(c)->m())); ctx->set_ignore_check(true); + std::stringstream errstrm; + ctx->set_regular_stream(errstrm); if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR); + SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str().c_str()); return; } @@ -178,7 +180,7 @@ extern "C" { char const* ext = get_extension(file_name); std::ifstream is(file_name); if (!is) { - SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR); + SET_ERROR_CODE(Z3_FILE_ACCESS_ERROR, nullptr); } else if (ext && std::string("dimacs") == ext) { ast_manager& m = to_solver_ref(s)->get_manager(); @@ -291,7 +293,7 @@ extern "C" { RESET_ERROR_CODE(); init_solver(c, s); if (n > to_solver_ref(s)->get_scope_level()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return; } if (n > 0) @@ -372,7 +374,7 @@ extern "C" { static Z3_lbool _solver_check(Z3_context c, Z3_solver s, unsigned num_assumptions, Z3_ast const assumptions[]) { for (unsigned i = 0; i < num_assumptions; i++) { if (!is_expr(to_ast(assumptions[i]))) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, "assumption is not an expression"); return Z3_L_UNDEF; } } @@ -430,7 +432,7 @@ extern "C" { model_ref _m; to_solver_ref(s)->get_model(_m); if (!_m) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "there is no current model"); RETURN_Z3(nullptr); } if (_m) { @@ -450,7 +452,7 @@ extern "C" { init_solver(c, s); proof * p = to_solver_ref(s)->get_proof(); if (!p) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "there is no current proof"); RETURN_Z3(nullptr); } mk_c(c)->save_ast_trail(p); @@ -542,7 +544,7 @@ extern "C" { for (ast* e : __assumptions) { if (!is_expr(e)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "assumption is not an expression"); return Z3_L_UNDEF; } _assumptions.push_back(to_expr(e)); @@ -551,7 +553,7 @@ extern "C" { for (ast* a : __variables) { if (!is_expr(a)) { _assumptions.finalize(); _consequences.finalize(); _variables.finalize(); - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "variable is not an expression"); return Z3_L_UNDEF; } _variables.push_back(to_expr(a)); @@ -593,7 +595,7 @@ extern "C" { expr_ref_vector result(m), vars(m); for (ast* a : to_ast_vector_ref(vs)) { if (!is_expr(a)) { - SET_ERROR_CODE(Z3_INVALID_USAGE); + SET_ERROR_CODE(Z3_INVALID_USAGE, "cube contains a non-expression"); } else { vars.push_back(to_expr(a)); diff --git a/src/api/api_stats.cpp b/src/api/api_stats.cpp index 2e1dac4de..2014d57b8 100644 --- a/src/api/api_stats.cpp +++ b/src/api/api_stats.cpp @@ -67,7 +67,7 @@ extern "C" { LOG_Z3_stats_get_key(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return to_stats_ref(s).get_key(idx); @@ -79,7 +79,7 @@ extern "C" { LOG_Z3_stats_is_uint(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_FALSE; } return to_stats_ref(s).is_uint(idx); @@ -91,7 +91,7 @@ extern "C" { LOG_Z3_stats_is_double(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return Z3_FALSE; } return !to_stats_ref(s).is_uint(idx); @@ -103,11 +103,11 @@ extern "C" { LOG_Z3_stats_get_uint_value(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0; } if (!to_stats_ref(s).is_uint(idx)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0; } return to_stats_ref(s).get_uint_value(idx); @@ -119,11 +119,11 @@ extern "C" { LOG_Z3_stats_get_double_value(c, s, idx); RESET_ERROR_CODE(); if (idx >= to_stats_ref(s).size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return 0.0; } if (to_stats_ref(s).is_uint(idx)) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return 0.0; } return to_stats_ref(s).get_double_value(idx); diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 345284fd6..7c0143201 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -52,7 +52,7 @@ extern "C" { RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); if (t == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } tactic * new_t = t->mk(mk_c(c)->m()); @@ -82,7 +82,7 @@ extern "C" { RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); if (p == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); RETURN_Z3(nullptr); } probe * new_p = p->get(); @@ -324,7 +324,7 @@ extern "C" { LOG_Z3_get_tactic_name(c, idx); RESET_ERROR_CODE(); if (idx >= mk_c(c)->num_tactics()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return mk_c(c)->get_tactic(idx)->get_name().bare_str(); @@ -344,7 +344,7 @@ extern "C" { LOG_Z3_get_probe_name(c, idx); RESET_ERROR_CODE(); if (idx >= mk_c(c)->num_probes()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); return ""; } return mk_c(c)->get_probe(idx)->get_name().bare_str(); @@ -381,7 +381,7 @@ extern "C" { RESET_ERROR_CODE(); tactic_cmd * t = mk_c(c)->find_tactic_cmd(symbol(name)); if (t == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return t->get_descr(); @@ -394,7 +394,7 @@ extern "C" { RESET_ERROR_CODE(); probe_info * p = mk_c(c)->find_probe(symbol(name)); if (p == nullptr) { - SET_ERROR_CODE(Z3_INVALID_ARG); + SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); return ""; } return p->get_descr(); @@ -504,7 +504,7 @@ extern "C" { LOG_Z3_apply_result_get_subgoal(c, r, i); RESET_ERROR_CODE(); if (i > to_apply_result(r)->m_subgoals.size()) { - SET_ERROR_CODE(Z3_IOB); + SET_ERROR_CODE(Z3_IOB, nullptr); RETURN_Z3(nullptr); } Z3_goal_ref * g = alloc(Z3_goal_ref, *mk_c(c)); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b68fb2021..a5021360d 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -169,7 +169,7 @@ namespace z3 { void check_parser_error() const { Z3_error_code e = Z3_get_error_code(*this); if (e != Z3_OK && enable_exceptions()) { - Z3_string s = Z3_get_parser_error(*this); + Z3_string s = Z3_get_error_message(*this); if (s && *s) Z3_THROW(exception(s)); } check_error(); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 10198fcc5..60a9bd734 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8395,11 +8395,6 @@ def _dict2darray(decls, ctx): i = i + 1 return sz, _names, _decls -def _handle_parse_error(ex, ctx): - msg = Z3_get_parser_error(ctx.ref()) - if msg != "": - raise Z3Exception(msg) - raise ex def parse_smt2_string(s, sorts={}, decls={}, ctx=None): """Parse a string in SMT 2.0 format using the given sorts and decls. @@ -8419,10 +8414,7 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - try: - return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) - except Z3Exception as e: - _handle_parse_error(e, ctx) + return AstVector(Z3_parse_smtlib2_string(ctx.ref(), s, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. @@ -8432,10 +8424,7 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) - try: - return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) - except Z3Exception as e: - _handle_parse_error(e, ctx) + return AstVector(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) ######################################### diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7e12f2fa7..9af548af0 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5280,12 +5280,6 @@ extern "C" { Z3_string Z3_API Z3_eval_smtlib2_string(Z3_context, Z3_string str); - /** - \brief Retrieve that last error message information generated from parsing. - - def_API('Z3_get_parser_error', STRING, (_in(CONTEXT), )) - */ - Z3_string Z3_API Z3_get_parser_error(Z3_context c); /*@}*/ /** @name Error Handling */ @@ -5332,11 +5326,6 @@ extern "C" { */ Z3_string Z3_API Z3_get_error_msg(Z3_context c, Z3_error_code err); - /** - \brief Return a string describing the given error code. - Retained function name for backwards compatibility within v4.1 - */ - Z3_string Z3_API Z3_get_error_msg_ex(Z3_context c, Z3_error_code err); /*@}*/ /** @name Miscellaneous */ diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index d5d2ee558..203ca2ca0 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -716,3 +716,24 @@ bool is_equal(goal const & s1, goal const & s2) { SASSERT(num1 >= num2); return num1 == num2; } + +bool goal::is_cnf() const { + for (unsigned i = 0; i < size(); i++) { + expr * f = form(i); + if (m_manager.is_or(f)) { + for (expr* l : *to_app(f)) { + if (!is_literal(f)) return false; + } + } + if (!is_literal(f)) return false; + } + return true; +} + +bool goal::is_literal(expr* f) const { + m_manager.is_not(f, f); + if (!is_app(f)) return false; + if (to_app(f)->get_family_id() == m_manager.get_basic_family_id() && + !m_manager.is_false(f) && !m_manager.is_true(f)) return false; + return true; +} diff --git a/src/tactic/goal.h b/src/tactic/goal.h index 2d91bc67f..4125fab99 100644 --- a/src/tactic/goal.h +++ b/src/tactic/goal.h @@ -77,7 +77,7 @@ protected: unsigned get_not_idx(expr * f) const; void shrink(unsigned j); void reset_core(); - + bool is_literal(expr* f) const; public: goal(ast_manager & m, bool models_enabled = true, bool core_enabled = false); @@ -159,6 +159,8 @@ public: void set(model_converter* m) { m_mc = m; } void set(proof_converter* p) { m_pc = p; } + bool is_cnf() const; + goal * translate(ast_translation & translator) const; }; From f4abb7eb48cadcd9428112c10f9bd286e845c9e8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jul 2018 16:26:05 -0700 Subject: [PATCH 008/118] fix c++ Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a5021360d..e1f263e17 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -167,11 +167,6 @@ namespace z3 { } void check_parser_error() const { - Z3_error_code e = Z3_get_error_code(*this); - if (e != Z3_OK && enable_exceptions()) { - Z3_string s = Z3_get_error_message(*this); - if (s && *s) Z3_THROW(exception(s)); - } check_error(); } From adb9a1c7978d236ce1d177c775905079db681e96 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Jul 2018 17:31:26 -0700 Subject: [PATCH 009/118] fix c Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index a6937f293..14e403826 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1754,7 +1754,6 @@ void parser_example5() { err: printf("Z3 error: %s.\n", Z3_get_error_msg(ctx, e)); if (ctx != NULL) { - printf("Error message: '%s'.\n",Z3_get_parser_error(ctx)); del_solver(ctx, s); Z3_del_context(ctx); } From f96133f4d93a70e08fe1030c23289437f404e442 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jul 2018 07:17:08 -0700 Subject: [PATCH 010/118] fix #1729 Signed-off-by: Nikolaj Bjorner --- src/api/api_goal.cpp | 4 +-- src/api/z3_api.h | 5 ++++ .../bit_blaster/bit_blaster_rewriter.cpp | 25 ++++++++++++++++--- src/tactic/goal.cpp | 6 +++-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index 090553df5..cb3bb7478 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -199,8 +199,8 @@ extern "C" { RESET_ERROR_CODE(); std::ostringstream buffer; if (!to_goal_ref(g)->is_cnf()) { - warning_msg("goal is not in CNF. This will produce a propositional abstraction. " - "If this is not what you want, then preprocess by optional bit-blasting and applying tseitin-cnf"); + SET_ERROR_CODE(Z3_INVALID_ARG, "If this is not what you want, then preprocess by optional bit-blasting and applying tseitin-cnf"); + RETURN_Z3(nullptr); } to_goal_ref(g)->display_dimacs(buffer); // Hack for removing the trailing '\n' diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 9af548af0..2657e558d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -5525,6 +5525,11 @@ extern "C" { /** \brief Convert a goal into a DIMACS formatted string. + The goal must be in CNF. You can convert a goal to CNF + by applying the tseitin-cnf tactic. Bit-vectors are not automatically + converted to Booleans either, so the caller intends to + preserve satisfiability, it should apply bit-blasting tactics. + Quantifiers and theory atoms will not be encoded. def_API('Z3_goal_to_dimacs_string', STRING, (_in(CONTEXT), _in(GOAL))) */ diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 862d1cdab..fe750acdd 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -89,6 +89,7 @@ struct blaster_rewriter_cfg : public default_rewriter_cfg { expr_ref_vector m_out; obj_map m_const2bits; expr_ref_vector m_bindings; + unsigned_vector m_shifts; func_decl_ref_vector m_keys; expr_ref_vector m_values; unsigned_vector m_keyval_lim; @@ -579,19 +580,36 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); } SASSERT(new_bindings.size() == q->get_num_decls()); i = q->get_num_decls(); + unsigned shift = j; + if (!m_shifts.empty()) shift += m_shifts.back(); while (i > 0) { i--; m_bindings.push_back(new_bindings[i]); + m_shifts.push_back(shift); } } return true; } bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { - if (m_blast_quant) { - if (t->get_idx() >= m_bindings.size()) + if (m_blast_quant) { + if (m_bindings.empty()) return false; - result = m_bindings.get(m_bindings.size() - t->get_idx() - 1); + unsigned shift = m_shifts.back(); + if (t->get_idx() >= m_bindings.size()) { + if (shift == 0) + return false; + result = m_manager.mk_var(t->get_idx() + shift, t->get_sort()); + } + else { + unsigned offset = m_bindings.size() - t->get_idx() - 1; + result = m_bindings.get(offset); + shift = shift - m_shifts[offset]; + if (shift > 0) { + var_shifter vs(m_manager); + vs(result, shift, result); + } + } result_pr = nullptr; return true; } @@ -641,6 +659,7 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); result_pr = nullptr; m_bindings.shrink(old_sz); + m_shifts.shrink(old_sz); return true; } }; diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index 203ca2ca0..f00f0e77e 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -733,7 +733,9 @@ bool goal::is_cnf() const { bool goal::is_literal(expr* f) const { m_manager.is_not(f, f); if (!is_app(f)) return false; - if (to_app(f)->get_family_id() == m_manager.get_basic_family_id() && - !m_manager.is_false(f) && !m_manager.is_true(f)) return false; + if (to_app(f)->get_family_id() == m_manager.get_basic_family_id()) { + for (expr* arg : *to_app(f)) + if (m_manager.is_bool(arg)) return false; + } return true; } From eceb92f5ef03a92446761a92b4af34ef40369e89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jul 2018 09:50:39 -0700 Subject: [PATCH 011/118] add utilities for purification Signed-off-by: Nikolaj Bjorner --- src/qe/qe_mbi.cpp | 42 +++++++++++++++++++++++- src/qe/qe_term_graph.cpp | 70 +++++++++++++++++++++++++++++++++------- src/qe/qe_term_graph.h | 13 ++++++++ 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/qe/qe_mbi.cpp b/src/qe/qe_mbi.cpp index 7dfa35003..b7f0d0d49 100644 --- a/src/qe/qe_mbi.cpp +++ b/src/qe/qe_mbi.cpp @@ -346,10 +346,50 @@ namespace qe { func_decl_ref_vector no_shared(m); tg1.set_vars(no_shared, false); tg1.add_lits(lits); + arith_util a(m); + expr_ref_vector foreign = tg1.shared_occurrences(a.get_family_id()); + obj_hashtable _foreign; + for (expr* e : foreign) _foreign.insert(e); + vector partition = tg1.get_partition(*mdl); expr_ref_vector diseq = tg1.get_ackerman_disequalities(); lits.append(diseq); - TRACE("qe", tout << "diseq: " << diseq << "\n";); + TRACE("qe", tout << "diseq: " << diseq << "\n"; + tout << "foreign: " << foreign << "\n"; + for (auto const& v : partition) { + tout << "partition: {"; + bool first = true; + for (expr* e : v) { + if (first) first = false; else tout << ", "; + tout << expr_ref(e, m); + } + tout << "}\n"; + } + ); + vector refined_partition; + for (auto & p : partition) { + unsigned j = 0; + for (expr* e : p) { + if (_foreign.contains(e) || + (is_app(e) && m_shared.contains(to_app(e)->get_decl()))) { + p[j++] = e; + } + } + p.shrink(j); + if (!p.empty()) refined_partition.push_back(p); + } + TRACE("qe", + for (auto const& v : refined_partition) { + tout << "partition: {"; + bool first = true; + for (expr* e : v) { + if (first) first = false; else tout << ", "; + tout << expr_ref(e, m); + } + tout << "}\n"; + }); + + arith_project_plugin ap(m); ap.set_check_purified(false); diff --git a/src/qe/qe_term_graph.cpp b/src/qe/qe_term_graph.cpp index 2e81454a0..faa9cfed8 100644 --- a/src/qe/qe_term_graph.cpp +++ b/src/qe/qe_term_graph.cpp @@ -99,7 +99,7 @@ namespace qe { m_mark(false), m_mark2(false), m_interpreted(false) { - if (!is_app()) return; + if (!is_app(m_expr)) return; for (expr* e : *to_app(m_expr)) { term* t = app2term[e->get_id()]; t->get_root().m_parents.push_back(this); @@ -151,7 +151,7 @@ namespace qe { unsigned get_id() const { return m_expr->get_id();} - unsigned get_decl_id() const { return is_app() ? get_app()->get_decl()->get_id() : m_expr->get_id(); } + unsigned get_decl_id() const { return is_app(m_expr) ? to_app(m_expr)->get_decl()->get_id() : m_expr->get_id(); } bool is_marked() const {return m_mark;} void set_mark(bool v){m_mark = v;} @@ -159,12 +159,10 @@ namespace qe { void set_mark2(bool v){m_mark2 = v;} // NSB: where is this used? bool is_interpreted() const {return m_interpreted;} - bool is_theory() const { return !is_app() || get_app()->get_family_id() != null_family_id; } + bool is_theory() const { return !is_app(m_expr) || to_app(m_expr)->get_family_id() != null_family_id; } void mark_as_interpreted() {m_interpreted=true;} expr* get_expr() const {return m_expr;} - bool is_app() const {return ::is_app(m_expr);} - app *get_app() const {return is_app() ? to_app(m_expr) : nullptr;} - unsigned get_num_args() const { return is_app() ? get_app()->get_num_args() : 0; } + unsigned get_num_args() const { return is_app(m_expr) ? to_app(m_expr)->get_num_args() : 0; } term &get_root() const {return *m_root;} bool is_root() const {return m_root == this;} @@ -226,7 +224,7 @@ namespace qe { } bool term_graph::is_variable_proc::operator()(const term &t) const { - return (*this)(t.get_app()); + return (*this)(t.get_expr()); } void term_graph::is_variable_proc::set_decls(const func_decl_ref_vector &decls, bool exclude) { @@ -444,7 +442,7 @@ namespace qe { return expr_ref(res, m); } - res = mk_app_core (r.get_app()); + res = mk_app_core (r.get_expr()); m_term2app.insert(r.get_id(), res); return expr_ref(res, m); @@ -463,7 +461,7 @@ namespace qe { SASSERT(t.is_root()); expr_ref rep(mk_app(t), m); for (term *it = &t.get_next(); it != &t; it = &it->get_next()) { - expr* mem = mk_app_core(it->get_app()); + expr* mem = mk_app_core(it->get_expr()); out.push_back (m.mk_eq (rep, mem)); } } @@ -472,9 +470,9 @@ namespace qe { mk_equalities(t, out); for (term *it = &t.get_next(); it != &t; it = &it->get_next ()) { - expr* a1 = mk_app_core (it->get_app()); + expr* a1 = mk_app_core (it->get_expr()); for (term *it2 = &it->get_next(); it2 != &t; it2 = &it2->get_next()) { - expr* a2 = mk_app_core(it2->get_app()); + expr* a2 = mk_app_core(it2->get_expr()); out.push_back (m.mk_eq (a1, a2)); } } @@ -1000,6 +998,47 @@ namespace qe { reset(); return res; } + + vector get_partition(model& mdl) { + vector result; + expr_ref_vector pinned(m); + obj_map pid; + model::scoped_model_completion _smc(mdl, true); + for (term *t : m_tg.m_terms) { + expr* a = t->get_expr(); + if (!is_app(a)) continue; + if (m.is_bool(a)) continue; + expr_ref val = mdl(a); + unsigned p = 0; + // NB. works for simple domains Integers, Rationals, + // but not for algebraic numerals. + if (!pid.find(val, p)) { + p = pid.size(); + pid.insert(val, p); + pinned.push_back(val); + result.push_back(expr_ref_vector(m)); + } + result[p].push_back(a); + } + return result; + } + + expr_ref_vector shared_occurrences(family_id fid) { + expr_ref_vector result(m); + for (term *t : m_tg.m_terms) { + expr* e = t->get_expr(); + if (m.get_sort(e)->get_family_id() != fid) continue; + for (term * p : term::parents(t->get_root())) { + expr* pe = p->get_expr(); + if (!is_app(pe)) continue; + if (to_app(pe)->get_family_id() == fid) continue; + if (to_app(pe)->get_family_id() == m.get_basic_family_id()) continue; + result.push_back(e); + break; + } + } + return result; + } }; void term_graph::set_vars(func_decl_ref_vector const& decls, bool exclude) { @@ -1033,5 +1072,14 @@ namespace qe { return p.get_ackerman_disequalities(); } + vector term_graph::get_partition(model& mdl) { + term_graph::projector p(*this); + return p.get_partition(mdl); + } + + expr_ref_vector term_graph::shared_occurrences(family_id fid) { + term_graph::projector p(*this); + return p.shared_occurrences(fid); + } } diff --git a/src/qe/qe_term_graph.h b/src/qe/qe_term_graph.h index 8c02163ab..855a0f2bc 100644 --- a/src/qe/qe_term_graph.h +++ b/src/qe/qe_term_graph.h @@ -122,6 +122,19 @@ namespace qe { */ expr_ref_vector get_ackerman_disequalities(); + /** + * Produce a model-based partition. + */ + vector get_partition(model& mdl); + + /** + * Extract shared occurrences of terms whose sort are + * fid, but appear in a context that is not fid. + * for example f(x + y) produces the shared occurrence + * x + y when f is uninterpreted and x + y has sort Int or Real. + */ + expr_ref_vector shared_occurrences(family_id fid); + }; } From 1918395f0eabad5038d8a97f2fe16855a27c4fa9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 5 Jul 2018 12:19:03 -0700 Subject: [PATCH 012/118] fix bug in sat-solver where frozen clauses get re-attached Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 12 ++++++++---- src/sat/sat_solver.h | 4 ++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a59dd2b46..04a0274c4 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -17,6 +17,7 @@ Revision History: --*/ + #include #include "sat/sat_solver.h" #include "sat/sat_integrity_checker.h" @@ -298,6 +299,9 @@ namespace sat { if (!c.is_learned()) { m_stats.m_non_learned_generation++; } + if (c.frozen()) { + --m_num_frozen; + } if (m_config.m_drat && !m_drat.is_cleaned(c)) { m_drat.del(c); } @@ -481,9 +485,10 @@ namespace sat { } unsigned some_idx = c.size() >> 1; literal block_lit = c[some_idx]; - DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); - DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) VERIFY(!w.is_clause() || w.get_clause_offset() != cls_off);); - VERIFY(c[0] != c[1]); + VERIFY(!c.frozen()); + DEBUG_CODE(for (auto const& w : m_watches[(~c[0]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); + DEBUG_CODE(for (auto const& w : m_watches[(~c[1]).index()]) SASSERT(!w.is_clause() || w.get_clause_offset() != cls_off);); + SASSERT(c[0] != c[1]); m_watches[(~c[0]).index()].push_back(watched(block_lit, cls_off)); m_watches[(~c[1]).index()].push_back(watched(block_lit, cls_off)); return reinit; @@ -2139,7 +2144,6 @@ namespace sat { else { c.inc_inact_rounds(); if (c.inact_rounds() > m_config.m_gc_k) { - m_num_frozen--; del_clause(c); m_stats.m_gc_clause++; deleted++; diff --git a/src/sat/sat_solver.h b/src/sat/sat_solver.h index b44c04604..ad972b2af 100644 --- a/src/sat/sat_solver.h +++ b/src/sat/sat_solver.h @@ -682,10 +682,10 @@ namespace sat { bool m_deleted; public: scoped_detach(solver& s, clause& c): s(s), c(c), m_deleted(false) { - s.detach_clause(c); + if (!c.frozen()) s.detach_clause(c); } ~scoped_detach() { - if (!m_deleted) s.attach_clause(c); + if (!m_deleted && !c.frozen()) s.attach_clause(c); } void del_clause() { From 905282ffe4ec675d96d80a059ede62815b2a790a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Jul 2018 14:47:05 -0700 Subject: [PATCH 013/118] fix in theory_lra.cpp get_value Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 6b8d7a47d..b4415264b 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1168,7 +1168,9 @@ public: if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - SASSERT (m_solver->is_term(vi)); + if(!m_solver->is_term(vi)) + return rational::zero(); + m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { From 852df6f7d9cec0fc138eadfbada3dec87e97b96c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Jul 2018 16:35:05 -0700 Subject: [PATCH 014/118] reshufle var_register to faster access Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 5 ----- src/util/lp/lar_solver.h | 2 -- src/util/lp/var_register.h | 46 ++++++++++++++++++-------------------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 8b5d8814a..6fec5b329 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1507,11 +1507,6 @@ bool lar_solver::column_is_fixed(unsigned j) const { return m_mpq_lar_core_solver.column_is_fixed(j); } - -bool lar_solver::ext_var_is_int(var_index ext_var) const { - return m_var_register.external_is_int(ext_var); -} - // below is the initialization functionality of lar_solver bool lar_solver::strategy_is_undecided() const { diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 9f79ff835..f17aa4a0d 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -155,8 +155,6 @@ public: bool var_is_int(var_index v) const; - bool ext_var_is_int(var_index ext_var) const; - void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int); void add_new_var_to_core_fields_for_doubles(bool register_in_basis); diff --git a/src/util/lp/var_register.h b/src/util/lp/var_register.h index 86c238e12..93404bf91 100644 --- a/src/util/lp/var_register.h +++ b/src/util/lp/var_register.h @@ -19,19 +19,19 @@ Revision History: #pragma once namespace lp { class ext_var_info { - unsigned m_internal_j; // the internal index + unsigned m_external_j; // the internal index bool m_is_integer; public: ext_var_info() {} ext_var_info(unsigned j): ext_var_info(j, true) {} - ext_var_info(unsigned j , bool is_int) : m_internal_j(j), m_is_integer(is_int) {} - unsigned internal_j() const { return m_internal_j;} + ext_var_info(unsigned j , bool is_int) : m_external_j(j), m_is_integer(is_int) {} + unsigned external_j() const { return m_external_j;} bool is_integer() const {return m_is_integer;} }; class var_register { - svector m_local_to_external; - std::unordered_map m_external_to_local; + svector m_local_to_external; + std::unordered_map m_external_to_local; public: unsigned add_var(unsigned user_var) { return add_var(user_var, true); @@ -39,19 +39,23 @@ public: unsigned add_var(unsigned user_var, bool is_int) { auto t = m_external_to_local.find(user_var); if (t != m_external_to_local.end()) { - return t->second.internal_j(); + return t->second; } - unsigned j = size(); - m_external_to_local[user_var] = ext_var_info(j, is_int); - m_local_to_external.push_back(user_var); - return j; + m_local_to_external.push_back(ext_var_info(user_var, is_int)); + return m_external_to_local[user_var] = size() - 1; } - const svector & vars() const { return m_local_to_external; } + svector vars() const { + svector ret; + for (const auto& p : m_local_to_external) { + ret.push_back(p.external_j()); + } + return ret; + } unsigned local_to_external(unsigned local_var) const { - return m_local_to_external[local_var]; + return m_local_to_external[local_var].external_j(); } unsigned size() const { return m_local_to_external.size(); @@ -64,13 +68,7 @@ public: unsigned external_to_local(unsigned j) const { auto it = m_external_to_local.find(j); lp_assert(it != m_external_to_local.end()); - return it->second.internal_j(); - } - - bool external_is_int(unsigned j) const { - auto it = m_external_to_local.find(j); - lp_assert(it != m_external_to_local.end()); - return it->second.is_integer(); + return it->second; } bool external_is_used(unsigned ext_j) const { @@ -82,7 +80,7 @@ public: auto it = m_external_to_local.find(ext_j); if ( it == m_external_to_local.end()) return false; - local_j = it->second.internal_j(); + local_j = it->second; return true; } @@ -90,19 +88,19 @@ public: auto it = m_external_to_local.find(ext_j); if ( it == m_external_to_local.end()) return false; - local_j = it->second.internal_j(); - is_int = it->second.is_integer(); + local_j = it->second; + is_int = m_local_to_external[local_j].is_integer(); return true; } bool local_is_int(unsigned j) const { - return external_is_int(m_local_to_external[j]); + return m_local_to_external[j].is_integer(); } void shrink(unsigned shrunk_size) { for (unsigned j = size(); j-- > shrunk_size;) { - m_external_to_local.erase(m_local_to_external[j]); + m_external_to_local.erase(m_local_to_external[j].external_j()); } m_local_to_external.resize(shrunk_size); } From c3035de44e75697d5842649bb37ccd2c8bc54216 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 01:49:13 -0700 Subject: [PATCH 015/118] logging in sorting network Signed-off-by: Nikolaj Bjorner --- src/util/sorting_network.h | 78 +++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index f2906b00c..2a0d929dd 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -177,8 +177,8 @@ Notes: // for testing static const bool m_disable_dcard = false; - static const bool m_disable_dsorting = false; - static const bool m_disable_dsmerge = false; + static const bool m_disable_dsorting = true; // false; + static const bool m_disable_dsmerge = true; // false; static const bool m_force_dcard = false; static const bool m_force_dsorting = false; static const bool m_force_dsmerge = false; @@ -611,7 +611,7 @@ Notes: in.push_back(ctx.mk_not(xs[i])); } TRACE("pb_verbose", - pp(tout << N << ": ", in); + //pp(tout << N << ": ", in); tout << " ~ " << k << "\n";); return true; } @@ -696,18 +696,21 @@ Notes: psort_nw::sorting(n, xs, out); } else if (use_dcard(k, n)) { + TRACE("pb_verbose", tout << "use dcard\n";); dsorting(k, n, xs, out); } else { + TRACE("pb_verbose", tout << "use merge\n";); literal_vector out1, out2; - unsigned l = n/2; // TBD - card(k, l, xs, out1); - card(k, n-l, xs + l, out2); + unsigned half = n/2; // TBD + card(k, half, xs, out1); + card(k, n-half, xs + half, out2); smerge(k, out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); } TRACE("pb_verbose", tout << "card k: " << k << " n: " << n << "\n"; - pp(tout << "in:", n, xs) << "\n"; - pp(tout << "out:", out) << "\n";); + //pp(tout << "in:", n, xs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } vc vc_card(unsigned k, unsigned n) { @@ -733,7 +736,7 @@ Notes: void merge(unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; if (a == 1 && b == 1) { literal y1 = mk_max(as[0], bs[0]); literal y2 = mk_min(as[0], bs[0]); @@ -768,10 +771,12 @@ Notes: odd_b.size(), odd_b.c_ptr(), out2); interleave(out1, out2, out); } - TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << "\n"; - pp(tout << "a:", a, as) << "\n"; - pp(tout << "b:", b, bs) << "\n"; - pp(tout << "out:", out) << "\n";); + TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + //pp(tout << "a:", a, as) << "\n"; + //pp(tout << "b:", b, bs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } vc vc_merge(unsigned a, unsigned b) { if (a == 1 && b == 1) { @@ -805,7 +810,7 @@ Notes: void interleave(literal_vector const& as, literal_vector const& bs, literal_vector& out) { - TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; SASSERT(as.size() >= bs.size()); SASSERT(as.size() <= bs.size() + 2); SASSERT(!as.empty()); @@ -825,10 +830,12 @@ Notes: out.push_back(as[sz+1]); } SASSERT(out.size() == as.size() + bs.size()); - TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << "\n"; - pp(tout << "a: ", as) << "\n"; - pp(tout << "b: ", bs) << "\n"; - pp(tout << "out: ", out) << "\n";); + TRACE("pb_verbose", tout << "interleave: " << as.size() << " " << bs.size() << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + //pp(tout << "a: ", as) << "\n"; + //pp(tout << "b: ", bs) << "\n"; + //pp(tout << "out: ", out) << "\n"; + ); } vc vc_interleave(unsigned a, unsigned b) { @@ -849,13 +856,15 @@ Notes: break; default: if (use_dsorting(n)) { + TRACE("pb_verbose", tout << "use dsorting: " << n << "\n";); dsorting(n, n, xs, out); } else { + TRACE("pb_verbose", tout << "use merge: " << n << "\n";); literal_vector out1, out2; - unsigned l = n/2; // TBD - sorting(l, xs, out1); - sorting(n-l, xs+l, out2); + unsigned half = n/2; // TBD + sorting(half, xs, out1); + sorting(n-half, xs+half, out2); merge(out1.size(), out1.c_ptr(), out2.size(), out2.c_ptr(), out); @@ -863,8 +872,9 @@ Notes: break; } TRACE("pb_verbose", tout << "sorting: " << n << "\n"; - pp(tout << "in:", n, xs) << "\n"; - pp(tout << "out:", out) << "\n";); + //pp(tout << "in:", n, xs) << "\n"; + //pp(tout << "out:", out) << "\n"; + ); } private: @@ -898,7 +908,7 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; if (a == 1 && b == 1 && c == 1) { literal y = mk_max(as[0], bs[0]); if (m_t != GE) { @@ -972,10 +982,11 @@ Notes: out.push_back(y); } } - TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << "\n"; - pp(tout << "a:", a, as) << "\n"; - pp(tout << "b:", b, bs) << "\n"; - pp(tout << "out:", out) << "\n"; + TRACE("pb_verbose", tout << "smerge: c:" << c << " a:" << a << " b:" << b << " "; + tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + //pp(tout << "a:", a, as) << "\n"; + //pp(tout << "b:", b, bs) << "\n"; + //pp(tout << "out:", out) << "\n"; ); SASSERT(out.size() == std::min(a + b, c)); } @@ -1007,7 +1018,7 @@ Notes: return m_force_dsmerge || (!m_disable_dsmerge && - a < (1 << 15) && b < (1 << 15) && + a < (1 << 7) && b < (1 << 7) && vc_dsmerge(a, b, a + b) < vc_smerge_rec(a, b, c)); } @@ -1075,9 +1086,9 @@ Notes: void dsorting(unsigned m, unsigned n, literal const* xs, literal_vector& out) { - TRACE("pb_verbose", tout << "dsorting m: " << m << " n: " << n << "\n";); SASSERT(m <= n); literal_vector lits; + unsigned nc = m_stats.m_num_compiled_clauses; for (unsigned i = 0; i < m; ++i) { out.push_back(fresh("dsort")); } @@ -1095,7 +1106,11 @@ Notes: lits.pop_back(); } } + TRACE("pb_verbose", + tout << "dsorting m: " << m << " n: " << n << " "; + tout << "num clauses: " << m_stats.m_num_compiled_clauses - nc << "\n";); } + vc vc_dsorting(unsigned m, unsigned n) { SASSERT(m <= n && n < 10); vc v(m, 0); @@ -1111,7 +1126,8 @@ Notes: void add_subset(bool polarity, unsigned k, unsigned offset, literal_vector& lits, unsigned n, literal const* xs) { TRACE("pb_verbose", tout << "k:" << k << " offset: " << offset << " n: " << n << " "; - pp(tout, lits) << "\n";); + //pp(tout, lits) << "\n"; + ); SASSERT(k + offset <= n); if (k == 0) { add_clause(lits); From 0b30ddb769ac2e83189d342cc8a403d9f05ebf9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 02:09:47 -0700 Subject: [PATCH 016/118] fix #1733 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b4415264b..b105def2c 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2763,12 +2763,12 @@ public: } case lp::lp_status::FEASIBLE: { inf_rational val(term_max.x, term_max.y); - // todo , TODO , not sure what happens here + blocker = mk_gt(v); return inf_eps(rational::zero(), val); } default: SASSERT(st == lp::lp_status::UNBOUNDED); - TRACE("arith", tout << "Unbounded v" << v << "\n";); + TRACE("arith", tout << "Unbounded v" << v << "\n";); has_shared = false; blocker = m.mk_false(); return inf_eps(rational::one(), inf_rational()); From a4057420372ec269b6356d6309f0ecd2bdf9459f Mon Sep 17 00:00:00 2001 From: nilsbecker Date: Fri, 6 Jul 2018 12:43:46 +0200 Subject: [PATCH 017/118] Adding comments --- src/smt/mam.cpp | 8 ++++++-- src/smt/smt_context.h | 2 +- src/smt/smt_quantifier.cpp | 6 ++++++ src/smt/smt_quantifier.h | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 51c39f9e2..a39fe96ed 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1847,6 +1847,9 @@ namespace smt { enode * m_n2; enode * m_app; const bind * m_b; + + // equalities used for pattern match. The first element of the tuple gives the argument (or null) of some term that was matched against some higher level + // structure of the trigger, the second element gives the term that argument is replaced with in order to match the trigger. Used for logging purposes only. vector> m_used_enodes; unsigned m_curr_used_enodes_size; ptr_vector m_pattern_instances; // collect the pattern instances... used for computing min_top_generation and max_top_generation @@ -2275,7 +2278,7 @@ namespace smt { if (m_ast_manager.has_trace_stream()) { m_used_enodes.reset(); - m_used_enodes.push_back(std::make_tuple(nullptr, n)); + m_used_enodes.push_back(std::make_tuple(nullptr, n)); // null indicates that n was matched against the trigger at the top-level } m_pc = t->get_root(); @@ -2381,6 +2384,7 @@ namespace smt { if (m_n1->get_root() != m_n2->get_root()) goto backtrack; + // we used the equality m_n1 = m_n2 for the match and need to make sure it ends up in the log m_used_enodes.push_back(std::make_tuple(m_n1, m_n2)); m_pc = m_pc->m_next; @@ -2777,7 +2781,7 @@ namespace smt { m_pattern_instances.pop_back(); m_pattern_instances.push_back(m_app); // continue succeeded - update_max_generation(m_app, nullptr); + update_max_generation(m_app, nullptr); // null indicates a top-level match TRACE("mam_int", tout << "continue next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); m_num_args = c->m_num_args; m_oreg = c->m_oreg; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 45d5f15d3..f3c3fc69f 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -959,7 +959,7 @@ namespace smt { bool contains_instance(quantifier * q, unsigned num_bindings, enode * const * bindings); bool add_instance(quantifier * q, app * pat, unsigned num_bindings, enode * const * bindings, unsigned max_generation, - unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes); + unsigned min_top_generation, unsigned max_top_generation, vector> & used_enodes /*gives the equalities used for the pattern match, see mam.cpp for more info*/); void set_global_generation(unsigned generation) { m_generation = generation; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 63297f829..0a522c072 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -204,9 +204,13 @@ namespace smt { if (f) { if (has_trace_stream()) { std::ostream & out = trace_stream(); + + // In the term produced by the quantifier instantiation the root of the equivalence class of the terms bound to the quantified variables + // is used. We need to make sure that all of these equalities appear in the log. for (unsigned i = 0; i < num_bindings; ++i) { log_justification_to_root(out, bindings[i]); } + for (auto n : used_enodes) { enode *orig = std::get<0>(n); enode *substituted = std::get<1>(n); @@ -215,6 +219,8 @@ namespace smt { log_justification_to_root(out, substituted); } } + + // At this point all relevant equalities for the match are logged. out << "[new-match] " << static_cast(f) << " #" << q->get_id() << " #" << pat->get_id(); for (unsigned i = 0; i < num_bindings; i++) { // I don't want to use mk_pp because it creates expressions for pretty printing. diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index 1b1c3547e..3c95d1e23 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -58,7 +58,7 @@ namespace smt { unsigned max_generation, unsigned min_top_generation, unsigned max_top_generation, - vector> & used_enodes); + vector> & used_enodes /*gives the equalities used for the pattern match, see mam.cpp for more info*/); bool add_instance(quantifier * q, unsigned num_bindings, enode * const * bindings, unsigned generation = 0); void init_search_eh(); From 3ae0ea824674df0ca53b03ec2a7e5f1d615a91a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 21:09:13 -0700 Subject: [PATCH 018/118] add circuit and unate encoding besides sorting option Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 31 +- src/opt/sortmax.cpp | 4 +- src/sat/ba_solver.cpp | 60 +++- src/sat/ba_solver.h | 4 +- src/sat/sat_params.pyg | 2 +- src/smt/theory_pb.cpp | 34 +- src/test/sorting_network.cpp | 66 ++-- src/util/sorting_network.h | 471 +++++++++++++++++++++------- 8 files changed, 488 insertions(+), 184 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 3862aecae..d1def83a1 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -865,8 +865,8 @@ struct pb2bv_rewriter::imp { // definitions used for sorting network pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_max(unsigned n, pliteral const* lits) { return trail(m.mk_or(n, lits)); } + pliteral mk_min(unsigned n, pliteral const* lits) { return trail(m.mk_and(n, lits)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_ismt2_pp(lit, m); } @@ -889,7 +889,7 @@ struct pb2bv_rewriter::imp { m_keep_cardinality_constraints = f; } - void set_at_most1(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } + void set_cardinality_encoding(sorting_network_encoding enc) { m_sort.cfg().m_encoding = enc; } }; @@ -904,7 +904,7 @@ struct pb2bv_rewriter::imp { card2bv_rewriter_cfg(imp& i, ast_manager & m):m_r(i, m) {} void keep_cardinality_constraints(bool f) { m_r.keep_cardinality_constraints(f); } void set_pb_solver(symbol const& s) { m_r.set_pb_solver(s); } - void set_at_most1(sorting_network_encoding enc) { m_r.set_at_most1(enc); } + void set_cardinality_encoding(sorting_network_encoding enc) { m_r.set_cardinality_encoding(enc); } }; @@ -916,7 +916,7 @@ struct pb2bv_rewriter::imp { m_cfg(i, m) {} void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } void set_pb_solver(symbol const& s) { m_cfg.set_pb_solver(s); } - void set_at_most1(sorting_network_encoding e) { m_cfg.set_at_most1(e); } + void set_cardinality_encoding(sorting_network_encoding e) { m_cfg.set_cardinality_encoding(e); } void rewrite(bool full, expr* e, expr_ref& r, proof_ref& p) { expr_ref ee(e, m()); if (m_cfg.m_r.mk_app(full, e, r)) { @@ -947,15 +947,17 @@ struct pb2bv_rewriter::imp { return gparams::get_module("sat").get_sym("pb.solver", symbol("solver")); } - sorting_network_encoding atmost1_encoding() const { - symbol enc = m_params.get_sym("atmost1_encoding", symbol()); + sorting_network_encoding cardinality_encoding() const { + symbol enc = m_params.get_sym("cardinality.encoding", symbol()); if (enc == symbol()) { - enc = gparams::get_module("sat").get_sym("atmost1_encoding", symbol()); + enc = gparams::get_module("sat").get_sym("cardinality.encoding", symbol()); } - if (enc == symbol("grouped")) return sorting_network_encoding::grouped_at_most_1; - if (enc == symbol("bimander")) return sorting_network_encoding::bimander_at_most_1; - if (enc == symbol("ordered")) return sorting_network_encoding::ordered_at_most_1; - return grouped_at_most_1; + if (enc == symbol("grouped")) return sorting_network_encoding::grouped_at_most; + if (enc == symbol("bimander")) return sorting_network_encoding::bimander_at_most; + if (enc == symbol("ordered")) return sorting_network_encoding::ordered_at_most; + if (enc == symbol("unate")) return sorting_network_encoding::unate_at_most; + if (enc == symbol("circuit")) return sorting_network_encoding::circuit_at_most; + return grouped_at_most; } @@ -973,10 +975,11 @@ struct pb2bv_rewriter::imp { m_params.append(p); m_rw.keep_cardinality_constraints(keep_cardinality()); m_rw.set_pb_solver(pb_solver()); - m_rw.set_at_most1(atmost1_encoding()); + m_rw.set_cardinality_encoding(cardinality_encoding()); } + void collect_param_descrs(param_descrs& r) const { - r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: true) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); + r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: false) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver"); r.insert("pb.solver", CPK_SYMBOL, "(default: solver) retain pb constraints (don't bit-blast them) and use built-in pb solver"); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 4313cfbec..1fafa12bd 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -124,8 +124,8 @@ namespace opt { // definitions used for sorting network pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_max(unsigned n, pliteral const* as) { return trail(m.mk_or(n, as)); } + pliteral mk_min(unsigned n, pliteral const* as) { return trail(m.mk_and(n, as)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 930617301..38cd07fa7 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -2591,22 +2591,54 @@ namespace sat { return literal(v, false); } - literal ba_solver::ba_sort::mk_max(literal l1, literal l2) { - VERIFY(l1 != null_literal); - VERIFY(l2 != null_literal); - if (l1 == m_true) return l1; - if (l2 == m_true) return l2; - if (l1 == ~m_true) return l2; - if (l2 == ~m_true) return l1; - literal max = fresh("max"); - s.s().mk_clause(~l1, max); - s.s().mk_clause(~l2, max); - s.s().mk_clause(~max, l1, l2); - return max; + + literal ba_solver::ba_sort::mk_max(unsigned n, literal const* lits) { + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) { + if (lits[i] == m_true) return m_true; + if (lits[i] == ~m_true) continue; + m_lits.push_back(lits[i]); + } + switch (m_lits.size()) { + case 0: + return ~m_true; + case 1: + return m_lits[0]; + default: { + literal max = fresh("max"); + for (unsigned i = 0; i < n; ++i) { + s.s().mk_clause(~m_lits[i], max); + } + m_lits.push_back(~max); + s.s().mk_clause(m_lits.size(), m_lits.c_ptr()); + return max; + } + } } - literal ba_solver::ba_sort::mk_min(literal l1, literal l2) { - return ~mk_max(~l1, ~l2); + literal ba_solver::ba_sort::mk_min(unsigned n, literal const* lits) { + m_lits.reset(); + for (unsigned i = 0; i < n; ++i) { + if (lits[i] == ~m_true) return ~m_true; + if (lits[i] == m_true) continue; + m_lits.push_back(lits[i]); + } + switch (m_lits.size()) { + case 0: + return m_true; + case 1: + return m_lits[0]; + default: { + literal min = fresh("min"); + for (unsigned i = 0; i < n; ++i) { + s.s().mk_clause(~min, m_lits[i]); + m_lits[i] = ~m_lits[i]; + } + m_lits.push_back(min); + s.s().mk_clause(m_lits.size(), m_lits.c_ptr()); + return min; + } + } } void ba_solver::ba_sort::mk_clause(unsigned n, literal const* lits) { diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index e947cee96..bae59f45a 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -255,8 +255,8 @@ namespace sat { pliteral mk_true(); pliteral mk_not(pliteral l); pliteral fresh(char const*); - pliteral mk_max(pliteral l1, pliteral l2); - pliteral mk_min(pliteral l1, pliteral l2); + pliteral mk_min(unsigned, pliteral const* lits); + pliteral mk_max(unsigned, pliteral const* lits); void mk_clause(unsigned n, literal const* lits); std::ostream& pp(std::ostream& out, pliteral l) const; }; diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index dd840468e..714bf0e24 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -43,7 +43,7 @@ def_module_params('sat', ('cardinality.solver', BOOL, True, 'use cardinality solver'), ('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use native solver)'), ('xor.solver', BOOL, False, 'use xor solver'), - ('atmost1_encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered'), + ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered, unate, circuit'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index ed0481938..e389c819e 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1429,23 +1429,27 @@ namespace smt { return literal(ctx.mk_bool_var(y)); } - literal mk_max(literal a, literal b) { - if (a == b) return a; - expr_ref t1(m), t2(m), t3(m); - ctx.literal2expr(a, t1); - ctx.literal2expr(b, t2); - t3 = m.mk_or(t1, t2); - bool_var v = ctx.b_internalized(t3)?ctx.get_bool_var(t3):ctx.mk_bool_var(t3); + literal mk_max(unsigned n, literal const* lits) { + expr_ref_vector es(m); + expr_ref tmp(m); + for (unsigned i = 0; i < n; ++i) { + ctx.literal2expr(lits[i], tmp); + es.push_back(tmp); + } + tmp = m.mk_or(es.size(), es.c_ptr()); + bool_var v = ctx.b_internalized(tmp)?ctx.get_bool_var(tmp):ctx.mk_bool_var(tmp); return literal(v); } - - literal mk_min(literal a, literal b) { - if (a == b) return a; - expr_ref t1(m), t2(m), t3(m); - ctx.literal2expr(a, t1); - ctx.literal2expr(b, t2); - t3 = m.mk_and(t1, t2); - bool_var v = ctx.b_internalized(t3)?ctx.get_bool_var(t3):ctx.mk_bool_var(t3); + + literal mk_min(unsigned n, literal const* lits) { + expr_ref_vector es(m); + expr_ref tmp(m); + for (unsigned i = 0; i < n; ++i) { + ctx.literal2expr(lits[i], tmp); + es.push_back(tmp); + } + tmp = m.mk_and(es.size(), es.c_ptr()); + bool_var v = ctx.b_internalized(tmp)?ctx.get_bool_var(tmp):ctx.mk_bool_var(tmp); return literal(v); } diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index f5c415c04..2470df528 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -134,16 +134,12 @@ void test_sorting3() { for (unsigned i = 0; i < 7; ++i) { in.push_back(m.mk_fresh_const("a",m.mk_bool_sort())); } - for (unsigned i = 0; i < in.size(); ++i) { - std::cout << mk_pp(in[i].get(), m) << "\n"; - } + for (expr* e : in) std::cout << mk_pp(e, m) << "\n"; ast_ext aext(m); sorting_network sn(aext); sn(in, out); std::cout << "size: " << out.size() << "\n"; - for (unsigned i = 0; i < out.size(); ++i) { - std::cout << mk_pp(out[i].get(), m) << "\n"; - } + for (expr* e : out) std::cout << mk_pp(e, m) << "\n"; } @@ -162,10 +158,12 @@ struct ast_ext2 { pliteral mk_false() { return m.mk_false(); } pliteral mk_true() { return m.mk_true(); } - pliteral mk_max(pliteral a, pliteral b) { - return trail(m.mk_or(a, b)); + pliteral mk_max(unsigned n, pliteral const* lits) { + return trail(m.mk_or(n, lits)); + } + pliteral mk_min(unsigned n, pliteral const* lits) { + return trail(m.mk_and(n, lits)); } - pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } @@ -199,8 +197,8 @@ static void test_eq1(unsigned n, sorting_network_encoding enc) { // equality: solver.push(); result1 = sn.eq(true, 1, in.size(), in.c_ptr()); - for (expr* cl : ext.m_clauses) { - solver.assert_expr(cl); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } expr_ref_vector ors(m); for (unsigned i = 0; i < n; ++i) { @@ -245,12 +243,15 @@ static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc std::cout << "eq " << k << " out of " << n << " for encoding " << enc << "\n"; solver.push(); result = sn.eq(false, k, in.size(), in.c_ptr()); - std::cout << result << "\n" << ext.m_clauses << "\n"; solver.assert_expr(result); for (expr* cl : ext.m_clauses) { solver.assert_expr(cl); } lbool res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + } ENSURE(res == l_true); solver.push(); @@ -258,6 +259,9 @@ static void test_sorting_eq(unsigned n, unsigned k, sorting_network_encoding enc solver.assert_expr(in[i].get()); } res = solver.check(); + if (res != l_true) { + std::cout << result << "\n" << ext.m_clauses << "\n"; + } ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); @@ -295,16 +299,26 @@ static void test_sorting_le(unsigned n, unsigned k, sorting_network_encoding enc solver.push(); result = sn.le(false, k, in.size(), in.c_ptr()); solver.assert_expr(result); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } lbool res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + std::cout << "clauses: " << ext.m_clauses << "\n"; + std::cout << "result: " << result << "\n"; + } ENSURE(res == l_true); for (unsigned i = 0; i < k; ++i) { solver.assert_expr(in[i].get()); } res = solver.check(); + if (res != l_true) { + std::cout << res << "\n"; + solver.display(std::cout); + } ENSURE(res == l_true); solver.assert_expr(in[k].get()); res = solver.check(); @@ -343,8 +357,8 @@ void test_sorting_ge(unsigned n, unsigned k, sorting_network_encoding enc) { solver.push(); result = sn.ge(false, k, in.size(), in.c_ptr()); solver.assert_expr(result); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } lbool res = solver.check(); ENSURE(res == l_true); @@ -407,13 +421,13 @@ void test_at_most_1(unsigned n, bool full, sorting_network_encoding enc) { std::cout << "clauses: " << ext.m_clauses << "\n-----\n"; - std::cout << "encoded: " << result1 << "\n"; - std::cout << "naive: " << result2 << "\n"; + //std::cout << "encoded: " << result1 << "\n"; + //std::cout << "naive: " << result2 << "\n"; smt_params fp; smt::kernel solver(m, fp); - for (unsigned i = 0; i < ext.m_clauses.size(); ++i) { - solver.assert_expr(ext.m_clauses[i].get()); + for (expr* cls : ext.m_clauses) { + solver.assert_expr(cls); } if (full) { solver.push(); @@ -481,8 +495,8 @@ static void test_at_most1(sorting_network_encoding enc) { sn.cfg().m_encoding = enc; expr_ref result(m); result = sn.le(true, 1, in.size(), in.c_ptr()); - std::cout << result << "\n"; - std::cout << ext.m_clauses << "\n"; + //std::cout << result << "\n"; + //std::cout << ext.m_clauses << "\n"; } static void test_sorting5(sorting_network_encoding enc) { @@ -509,9 +523,11 @@ static void tst_sorting_network(sorting_network_encoding enc) { } void tst_sorting_network() { - tst_sorting_network(sorting_network_encoding::ordered_at_most_1); - tst_sorting_network(sorting_network_encoding::grouped_at_most_1); - tst_sorting_network(sorting_network_encoding::bimander_at_most_1); + tst_sorting_network(sorting_network_encoding::unate_at_most); + tst_sorting_network(sorting_network_encoding::circuit_at_most); + tst_sorting_network(sorting_network_encoding::ordered_at_most); + tst_sorting_network(sorting_network_encoding::grouped_at_most); + tst_sorting_network(sorting_network_encoding::bimander_at_most); test_sorting1(); test_sorting2(); test_sorting3(); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 2a0d929dd..d7d8e8bbe 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -25,16 +25,22 @@ Notes: #define SORTING_NETWORK_H_ enum sorting_network_encoding { - grouped_at_most_1, - bimander_at_most_1, - ordered_at_most_1 + sorted_at_most, + grouped_at_most, + bimander_at_most, + ordered_at_most, + unate_at_most, + circuit_at_most }; inline std::ostream& operator<<(std::ostream& out, sorting_network_encoding enc) { switch (enc) { - case grouped_at_most_1: return out << "grouped"; - case bimander_at_most_1: return out << "bimander"; - case ordered_at_most_1: return out << "ordered"; + case grouped_at_most: return out << "grouped"; + case bimander_at_most: return out << "bimander"; + case ordered_at_most: return out << "ordered"; + case sorted_at_most: return out << "sorted"; + case unate_at_most: return out << "unate"; + case circuit_at_most: return out << "circuit"; } return out << "???"; } @@ -42,7 +48,7 @@ Notes: struct sorting_network_config { sorting_network_encoding m_encoding; sorting_network_config() { - m_encoding = grouped_at_most_1; + m_encoding = sorted_at_most; } }; @@ -158,12 +164,19 @@ Notes: vc operator+(vc const& other) const { return vc(v + other.v, c + other.c); } + vc operator-(vc const& other) const { + return vc(v - other.v, c - other.c); + } unsigned to_int() const { return lambda*v + c; } vc operator*(unsigned n) const { return vc(n*v, n*c); } + + std::ostream& pp(std::ostream& out) const { + return out << "v: " << v << " c: " << c; + } }; static vc mk_min(vc const& v1, vc const& v2) { @@ -176,13 +189,17 @@ Notes: cmp_t m_t; // for testing - static const bool m_disable_dcard = false; - static const bool m_disable_dsorting = true; // false; - static const bool m_disable_dsmerge = true; // false; + static const bool m_disable_dcard = false; + static const bool m_disable_dsorting = false; + static const bool m_disable_dsmerge = false; static const bool m_force_dcard = false; static const bool m_force_dsorting = false; static const bool m_force_dsmerge = false; + bool is_power_of2(unsigned n) const { + return n != 0 && ((n-1) & n) == 0; + } + public: struct stats { unsigned m_num_compiled_vars; @@ -221,15 +238,31 @@ Notes: } SASSERT(0 < k && k <= n); literal_vector in, out; + if (k == 1) { + return mk_or(n, xs); + } if (dualize(k, n, xs, in)) { return le(full, k, in.size(), in.c_ptr()); } else { - SASSERT(2*k <= n); - m_t = full?GE_FULL:GE; - // scoped_stats _ss(m_stats, k, n); - psort_nw::card(k, n, xs, out); - return out[k-1]; + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case ordered_at_most: + case grouped_at_most: + SASSERT(2*k <= n); + m_t = full?GE_FULL:GE; + // scoped_stats _ss(m_stats, k, n); + psort_nw::card(k, n, xs, out); + return out[k-1]; + case unate_at_most: + return unate_ge(full, k, n, xs); + case circuit_at_most: + return circuit_ge(full, k, n, xs); + default: + UNREACHABLE(); + return xs[0]; + } } } @@ -246,23 +279,40 @@ Notes: literal_vector ors; // scoped_stats _ss(m_stats, k, n); switch (m_cfg.m_encoding) { - case grouped_at_most_1: + case grouped_at_most: + case sorted_at_most: + case unate_at_most: + case circuit_at_most: return mk_at_most_1(full, n, xs, ors, false); - case bimander_at_most_1: + case bimander_at_most: return mk_at_most_1_bimander(full, n, xs, ors); - case ordered_at_most_1: + case ordered_at_most: return mk_ordered_atmost_1(full, n, xs); + default: UNREACHABLE(); return xs[0]; } } else { - SASSERT(2*k <= n); - m_t = full?LE_FULL:LE; - // scoped_stats _ss(m_stats, k, n); - card(k + 1, n, xs, out); - return ctx.mk_not(out[k]); + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case ordered_at_most: + case grouped_at_most: + SASSERT(2*k <= n); + m_t = full?LE_FULL:LE; + // scoped_stats _ss(m_stats, k, n); + card(k + 1, n, xs, out); + return mk_not(out[k]); + case unate_at_most: + return unate_le(full, k, n, xs); + case circuit_at_most: + return circuit_le(full, k, n, xs); + default: + UNREACHABLE(); + return xs[0]; + } } } @@ -280,16 +330,29 @@ Notes: return mk_exactly_1(full, n, xs); } else { - // scoped_stats _ss(m_stats, k, n); - SASSERT(2*k <= n); - m_t = EQ; - card(k+1, n, xs, out); - SASSERT(out.size() >= k+1); - if (k == 0) { - return ctx.mk_not(out[k]); - } - else { - return ctx.mk_min(out[k-1], ctx.mk_not(out[k])); + switch (m_cfg.m_encoding) { + case sorted_at_most: + case bimander_at_most: + case grouped_at_most: + case ordered_at_most: + // scoped_stats _ss(m_stats, k, n); + SASSERT(2*k <= n); + m_t = EQ; + card(k+1, n, xs, out); + SASSERT(out.size() >= k+1); + if (k == 0) { + return mk_not(out[k]); + } + else { + return mk_min(out[k-1], mk_not(out[k])); + } + case unate_at_most: + return unate_eq(k, n, xs); + case circuit_at_most: + return circuit_eq(k, n, xs); + default: + UNREACHABLE(); + return xs[0]; } } } @@ -297,49 +360,193 @@ Notes: private: + // perform unate addition up to k. + literal unate_cmp(cmp_t cmp, unsigned k, unsigned n, literal const* xs) { + unsigned last = k; + if (cmp == LE || cmp == EQ || cmp == LE_FULL) { + last = k + 1; + } + bool full = cmp == LE_FULL || cmp == GE_FULL; + + literal_vector carry; + for (unsigned i = 0; i < last; ++i) { + carry.push_back(ctx.mk_false()); + } + for (unsigned i = 0; i < n; ++i) { + for (unsigned j = last; j-- > 0; ) { + // c'[j] <-> (xs[i] & c[j-1]) | c[j] + literal c0 = j > 0 ? carry[j-1] : ctx.mk_true(); + carry[j] = mk_or(mk_and(xs[i], c0), carry[j]); + } + } + switch (cmp) { + case LE: + case LE_FULL: + return mk_not(carry[k]); + case GE: + case GE_FULL: + return carry[k-1]; + case EQ: + return mk_and(mk_not(carry[k]), carry[k-1]); + default: + UNREACHABLE(); + return xs[0]; + } + } + + literal unate_ge(bool full, unsigned k, unsigned n, literal const* xs) { + return unate_cmp(full ? GE_FULL : GE, k, n, xs); + } + + literal unate_le(bool full, unsigned k, unsigned n, literal const* xs) { + return unate_cmp(full ? LE_FULL : LE, k, n, xs); + } + + literal unate_eq(unsigned k, unsigned n, literal const* xs) { + return unate_cmp(EQ, k, n, xs); + } + + // circuit encoding + void mk_unit_circuit(unsigned k, literal x, literal_vector& out) { + out.push_back(x); + for (unsigned i = 1; i < k; ++i) out.push_back(ctx.mk_false()); + } + + literal mk_add_circuit(literal_vector const& x, literal_vector const& y, literal_vector& out) { + literal c = ctx.mk_false(); + SASSERT(x.size() == y.size()); + for (unsigned i = 0; i < x.size(); ++i) { + // out[i] = c + x[i] + y[i] + // c' = c&x[i] | c&y[i] | x[i]&y[i]; + literal_vector ors; + ors.push_back(mk_and(c, mk_not(x[i]), mk_not(y[i]))); + ors.push_back(mk_and(x[i], mk_not(c), mk_not(y[i]))); + ors.push_back(mk_and(y[i], mk_not(c), mk_not(x[i]))); + ors.push_back(mk_and(c, x[i], y[i])); + literal o = mk_or(4, ors.c_ptr()); + out.push_back(o); + ors[0] = mk_and(c, x[i]); + ors[1] = mk_and(c, y[i]); + ors[2] = mk_and(x[i], y[i]); + c = mk_or(3, ors.c_ptr()); + } + return c; + } + + literal circuit_add(unsigned k, unsigned n, literal const* xs, literal_vector& out) { + switch (n) { + case 0: + for (unsigned i = 0; i < k; ++i) { + out.push_back(ctx.mk_false()); + } + return ctx.mk_false(); + case 1: + mk_unit_circuit(k, xs[0], out); + return ctx.mk_false(); + default: { + literal_vector o1, o2; + unsigned half = n / 2; + literal ovfl1 = circuit_add(k, half, xs, o1); + literal ovfl2 = circuit_add(k, n - half, xs + half, o2); + literal ovfl3 = mk_add_circuit(o1, o2, out); + return mk_or(ovfl1, ovfl2, ovfl3); + } + } + } + + literal circuit_cmp(cmp_t cmp, unsigned k, unsigned n, literal const* xs) { + literal_vector out, kvec; + unsigned num_bits = 0; + unsigned k1 = (cmp == LE || cmp == LE_FULL) ? k + 1 : k; + unsigned k0 = k1; + while (k0 > 0) { ++num_bits; k0 >>= 1; } + for (unsigned i = 0; i < num_bits; ++i) { + kvec.push_back((0 != (k1 & (1 << i))) ? ctx.mk_true() : ctx.mk_false()); + } + literal ovfl = circuit_add(num_bits, n, xs, out); + switch (cmp) { + case LE: + case LE_FULL: + return mk_not(mk_or(ovfl, mk_ge(out, kvec))); + case GE: + case GE_FULL: + return mk_or(ovfl, mk_ge(out, kvec)); + case EQ: { + literal_vector eqs; + SASSERT(kvec.size() == out.size()); + for (unsigned i = 0; i < num_bits; ++i) { + eqs.push_back(mk_or(mk_not(kvec[i]), out[i])); + eqs.push_back(mk_or(kvec[i], mk_not(out[i]))); + } + eqs.push_back(mk_not(ovfl)); + return mk_and(eqs); + } + default: + UNREACHABLE(); + return xs[0]; + } + } + + literal mk_ge(literal_vector const& x, literal_vector const& y) { + literal r = ctx.mk_true(); + literal g = ctx.mk_false(); + for (unsigned j = x.size(); j-- > 0; ) { + g = mk_or(g, mk_and(r, mk_and(x[j], mk_not(y[j])))); + r = mk_or(g, mk_and(r, mk_or( x[j], mk_not(y[j])))); + } + return r; + } + + literal circuit_ge(bool full, unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(full ? GE_FULL : GE, k, n, xs); + } + + literal circuit_le(bool full, unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(full ? LE_FULL : LE, k, n, xs); + } + + literal circuit_eq(unsigned k, unsigned n, literal const* xs) { + return circuit_cmp(EQ, k, n, xs); + } + void add_implies_or(literal l, unsigned n, literal const* xs) { literal_vector lits(n, xs); - lits.push_back(ctx.mk_not(l)); + lits.push_back(mk_not(l)); add_clause(lits); } - void add_or_implies(literal l, unsigned n, literal const* xs) { - for (unsigned j = 0; j < n; ++j) { - add_clause(ctx.mk_not(xs[j]), l); + literal mk_or(unsigned n, literal const* _ors) { + literal_vector ors(n, _ors); + unsigned j = 0; + for (literal lit : ors) { + if (is_true(lit)) return lit; + if (!is_false(lit)) ors[j++] = lit; } - } - - literal mk_or(unsigned n, literal const* ors) { - if (n == 1) { - return ors[0]; + ors.shrink(j); + switch (j) { + case 0: return ctx.mk_false(); + case 1: return ors[0]; + default: return ctx.mk_max(ors.size(), ors.c_ptr()); } - literal result = fresh("or"); - add_implies_or(result, n, ors); - add_or_implies(result, n, ors); - return result; } literal mk_or(literal l1, literal l2) { literal ors[2] = { l1, l2 }; return mk_or(2, ors); } + literal mk_or(literal l1, literal l2, literal l3) { + literal ors[3] = { l1, l2, l3 }; + return mk_or(3, ors); + } + literal mk_or(literal_vector const& ors) { return mk_or(ors.size(), ors.c_ptr()); } - void add_implies_and(literal l, literal_vector const& xs) { - for (literal const& x : xs) { - add_clause(ctx.mk_not(l), x); - } - } - - void add_and_implies(literal l, literal_vector const& xs) { - literal_vector lits; - for (literal const& x : xs) { - lits.push_back(ctx.mk_not(x)); - } - lits.push_back(l); - add_clause(lits); + literal mk_not(literal lit) { + if (is_true(lit)) return ctx.mk_false(); + if (is_false(lit)) return ctx.mk_true(); + return ctx.mk_not(lit); } literal mk_and(literal l1, literal l2) { @@ -348,14 +555,39 @@ Notes: return mk_and(xs); } - literal mk_and(literal_vector const& ands) { - if (ands.size() == 1) { - return ands[0]; + literal mk_and(literal l1, literal l2, literal l3) { + literal_vector xs; + xs.push_back(l1); xs.push_back(l2); xs.push_back(l3); + return mk_and(xs); + } + + bool is_true(literal l) { + return l == ctx.mk_true(); + } + + bool is_false(literal l) { + return l == ctx.mk_false(); + } + + literal mk_and(literal_vector const& _ands) { + literal_vector ands(_ands); + unsigned j = 0; + for (literal lit : ands) { + if (is_false(lit)) return lit; + if (!is_true(lit)) ands[j++] = lit; + } + ands.shrink(j); + switch (j) { + case 0: + return ctx.mk_true(); + case 1: + return ands[0]; + case 2: + return mk_min(ands[0], ands[1]); + default: { + return ctx.mk_min(ands.size(), ands.c_ptr()); + } } - literal result = fresh("and"); - add_implies_and(result, ands); - add_and_implies(result, ands); - return result; } literal mk_exactly_1(bool full, unsigned n, literal const* xs) { @@ -363,13 +595,16 @@ Notes: literal_vector ors; literal r1; switch (m_cfg.m_encoding) { - case grouped_at_most_1: + case grouped_at_most: + case sorted_at_most: + case unate_at_most: + case circuit_at_most: r1 = mk_at_most_1(full, n, xs, ors, true); break; - case bimander_at_most_1: + case bimander_at_most: r1 = mk_at_most_1_bimander(full, n, xs, ors); break; - case ordered_at_most_1: + case ordered_at_most: return mk_ordered_exactly_1(full, n, xs); default: UNREACHABLE(); @@ -426,7 +661,7 @@ Notes: // result => xs[0] + ... + xs[n-1] <= 1 for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { - add_clause(ctx.mk_not(result), ctx.mk_not(xs[i]), ctx.mk_not(xs[j])); + add_clause(mk_not(result), mk_not(xs[i]), mk_not(xs[j])); } } @@ -441,7 +676,7 @@ Notes: } add_clause(lits); } - ands.push_back(ctx.mk_not(and_i)); + ands.push_back(mk_not(and_i)); } } @@ -457,7 +692,7 @@ Notes: literal_vector ands; for (unsigned i = 0; i < n; ++i) { for (unsigned j = i + 1; j < n; ++j) { - ands.push_back(mk_or(ctx.mk_not(xs[i]), ctx.mk_not(xs[j]))); + ands.push_back(mk_or(mk_not(xs[i]), mk_not(xs[j]))); } } return mk_and(ands); @@ -513,36 +748,36 @@ Notes: ys.push_back(fresh("y")); } for (unsigned i = 0; i + 2 < n; ++i) { - add_clause(ctx.mk_not(ys[i]), ys[i + 1]); + add_clause(mk_not(ys[i]), ys[i + 1]); } for (unsigned i = 0; i + 1 < n; ++i) { - add_clause(ctx.mk_not(xs[i]), ys[i]); - add_clause(ctx.mk_not(r), ctx.mk_not(ys[i]), ctx.mk_not(xs[i + 1])); + add_clause(mk_not(xs[i]), ys[i]); + add_clause(mk_not(r), mk_not(ys[i]), mk_not(xs[i + 1])); } if (is_eq) { - add_clause(ctx.mk_not(r), ys[n-2], xs[n-1]); + add_clause(mk_not(r), ys[n-2], xs[n-1]); } for (unsigned i = 1; i < n - 1; ++i) { - add_clause(ctx.mk_not(ys[i]), xs[i], ys[i-1]); + add_clause(mk_not(ys[i]), xs[i], ys[i-1]); } - add_clause(ctx.mk_not(ys[0]), xs[0]); + add_clause(mk_not(ys[0]), xs[0]); if (full) { literal_vector twos; for (unsigned i = 0; i < n - 1; ++i) { twos.push_back(fresh("two")); } - add_clause(ctx.mk_not(twos[0]), ys[0]); - add_clause(ctx.mk_not(twos[0]), xs[1]); + add_clause(mk_not(twos[0]), ys[0]); + add_clause(mk_not(twos[0]), xs[1]); for (unsigned i = 1; i < n - 1; ++i) { - add_clause(ctx.mk_not(twos[i]), ys[i], twos[i-1]); - add_clause(ctx.mk_not(twos[i]), xs[i + 1], twos[i-1]); + add_clause(mk_not(twos[i]), ys[i], twos[i-1]); + add_clause(mk_not(twos[i]), xs[i + 1], twos[i-1]); } if (is_eq) { literal zero = fresh("zero"); - add_clause(ctx.mk_not(zero), ctx.mk_not(xs[n-1])); - add_clause(ctx.mk_not(zero), ctx.mk_not(ys[n-2])); + add_clause(mk_not(zero), mk_not(xs[n-1])); + add_clause(mk_not(zero), mk_not(ys[n-2])); add_clause(r, zero, twos.back()); } else { @@ -579,7 +814,7 @@ Notes: for (unsigned i = 0; i < ors.size(); ++i) { for (unsigned k = 0; k < nbits; ++k) { bool bit_set = (i & (static_cast(1 << k))) != 0; - add_clause(ctx.mk_not(result), ctx.mk_not(ors[i]), bit_set ? bits[k] : ctx.mk_not(bits[k])); + add_clause(mk_not(result), mk_not(ors[i]), bit_set ? bits[k] : mk_not(bits[k])); } } return result; @@ -608,7 +843,7 @@ Notes: } k = N - k; for (unsigned i = 0; i < N; ++i) { - in.push_back(ctx.mk_not(xs[i])); + in.push_back(mk_not(xs[i])); } TRACE("pb_verbose", //pp(tout << N << ": ", in); @@ -627,13 +862,15 @@ Notes: literal mk_max(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.mk_max(a, b); + literal lits[2] = { a, b}; + return ctx.mk_max(2, lits); } literal mk_min(literal a, literal b) { if (a == b) return a; m_stats.m_num_compiled_vars++; - return ctx.mk_min(a, b); + literal lits[2] = { a, b}; + return ctx.mk_min(2, lits); } literal fresh(char const* n) { @@ -652,6 +889,9 @@ Notes: add_clause(lits.size(), lits.c_ptr()); } void add_clause(unsigned n, literal const* ls) { + for (unsigned i = 0; i < n; ++i) { + if (is_true(ls[i])) return; + } m_stats.m_num_compiled_clauses++; m_stats.m_num_clause_vars += n; literal_vector tmp(n, ls); @@ -661,17 +901,17 @@ Notes: // y1 <= mk_max(x1,x2) // y2 <= mk_min(x1,x2) void cmp_ge(literal x1, literal x2, literal y1, literal y2) { - add_clause(ctx.mk_not(y2), x1); - add_clause(ctx.mk_not(y2), x2); - add_clause(ctx.mk_not(y1), x1, x2); + add_clause(mk_not(y2), x1); + add_clause(mk_not(y2), x2); + add_clause(mk_not(y1), x1, x2); } // mk_max(x1,x2) <= y1 // mk_min(x1,x2) <= y2 void cmp_le(literal x1, literal x2, literal y1, literal y2) { - add_clause(ctx.mk_not(x1), y1); - add_clause(ctx.mk_not(x2), y1); - add_clause(ctx.mk_not(x1), ctx.mk_not(x2), y2); + add_clause(mk_not(x1), y1); + add_clause(mk_not(x2), y1); + add_clause(mk_not(x1), mk_not(x2), y2); } void cmp_eq(literal x1, literal x2, literal y1, literal y2) { @@ -773,6 +1013,8 @@ Notes: } TRACE("pb_verbose", tout << "merge a: " << a << " b: " << b << " "; tout << "num clauses " << m_stats.m_num_compiled_clauses - nc << "\n"; + vc_dsmerge(a, b, a + b).pp(tout << "vc_dsmerge ") << "\n"; + vc_smerge_rec(a, b, a + b).pp(tout << "vc_smerge_rec ") << "\n"; //pp(tout << "a:", a, as) << "\n"; //pp(tout << "b:", b, bs) << "\n"; //pp(tout << "out:", out) << "\n"; @@ -796,7 +1038,8 @@ Notes: return vc_merge(ceil2(a), ceil2(b)) + vc_merge(floor2(a), floor2(b)) + - vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b)); + vc_interleave(ceil2(a) + ceil2(b), floor2(a) + floor2(b)) - + vc(0, 2); } void split(unsigned n, literal const* ls, literal_vector& even, literal_vector& odd) { for (unsigned i = 0; i < n; i += 2) { @@ -914,12 +1157,12 @@ Notes: if (m_t != GE) { // x1 <= mk_max(x1,x2) // x2 <= mk_max(x1,x2) - add_clause(ctx.mk_not(as[0]), y); - add_clause(ctx.mk_not(bs[0]), y); + add_clause(mk_not(as[0]), y); + add_clause(mk_not(bs[0]), y); } if (m_t != LE) { // mk_max(x1,x2) <= x1, x2 - add_clause(ctx.mk_not(y), as[0], bs[0]); + add_clause(mk_not(y), as[0], bs[0]); } out.push_back(y); } @@ -970,11 +1213,11 @@ Notes: out2.pop_back(); y = mk_max(z1, z2); if (m_t != GE) { - add_clause(ctx.mk_not(z1), y); - add_clause(ctx.mk_not(z2), y); + add_clause(mk_not(z1), y); + add_clause(mk_not(z2), y); } if (m_t != LE) { - add_clause(ctx.mk_not(y), z1, z2); + add_clause(mk_not(y), z1, z2); } } interleave(out1, out2, out); @@ -1018,7 +1261,7 @@ Notes: return m_force_dsmerge || (!m_disable_dsmerge && - a < (1 << 7) && b < (1 << 7) && + a < 10 && b < 10 && vc_dsmerge(a, b, a + b) < vc_smerge_rec(a, b, c)); } @@ -1027,7 +1270,7 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - TRACE("pb_verbose", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << "\n";); + unsigned nc = m_stats.m_num_compiled_clauses; SASSERT(a <= c); SASSERT(b <= c); SASSERT(a + b >= c); @@ -1036,14 +1279,14 @@ Notes: } if (m_t != GE) { for (unsigned i = 0; i < a; ++i) { - add_clause(ctx.mk_not(as[i]), out[i]); + add_clause(mk_not(as[i]), out[i]); } for (unsigned i = 0; i < b; ++i) { - add_clause(ctx.mk_not(bs[i]), out[i]); + add_clause(mk_not(bs[i]), out[i]); } for (unsigned i = 1; i <= a; ++i) { for (unsigned j = 1; j <= b && i + j <= c; ++j) { - add_clause(ctx.mk_not(as[i-1]),ctx.mk_not(bs[j-1]),out[i+j-1]); + add_clause(mk_not(as[i-1]),mk_not(bs[j-1]),out[i+j-1]); } } } @@ -1051,12 +1294,12 @@ Notes: literal_vector ls; for (unsigned k = 0; k < c; ++k) { ls.reset(); - ls.push_back(ctx.mk_not(out[k])); + ls.push_back(mk_not(out[k])); if (a <= k) { - add_clause(ctx.mk_not(out[k]), bs[k-a]); + add_clause(mk_not(out[k]), bs[k-a]); } if (b <= k) { - add_clause(ctx.mk_not(out[k]), as[k-b]); + add_clause(mk_not(out[k]), as[k-b]); } for (unsigned i = 0; i < std::min(a,k + 1); ++i) { unsigned j = k - i; @@ -1071,7 +1314,13 @@ Notes: } } } + TRACE("pb_verbose", tout << "dsmerge: c:" << c << " a:" << a << " b:" << b << " "; + tout << "num clauses: " << m_stats.m_num_compiled_clauses - nc << "\n"; + vc_dsmerge(a, b, c).pp(tout << "vc_dsmerge ") << "\n"; + vc_smerge_rec(a, b, c).pp(tout << "vc_smerge_rec ") << "\n"; + ); } + vc vc_dsmerge(unsigned a, unsigned b, unsigned c) { vc v(c, 0); if (m_t != GE) { @@ -1101,7 +1350,7 @@ Notes: } if (m_t != LE) { for (unsigned k = 1; k <= m; ++k) { - lits.push_back(ctx.mk_not(out[k-1])); + lits.push_back(mk_not(out[k-1])); add_subset(false, n-k+1, 0, lits, n, xs); lits.pop_back(); } @@ -1134,7 +1383,7 @@ Notes: return; } for (unsigned i = offset; i < n - k + 1; ++i) { - lits.push_back(polarity?ctx.mk_not(xs[i]):xs[i]); + lits.push_back(polarity?mk_not(xs[i]):xs[i]); add_subset(polarity, k-1, i+1, lits, n, xs); lits.pop_back(); } From e4ae80b3f23ad35b6fffb71ded2319764b4cd60c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 21:25:38 -0700 Subject: [PATCH 019/118] update documentation for renamed parameter Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith_plugin.cpp | 14 +++++++------- src/sat/sat_params.pyg | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 21e50182f..f8c519285 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -1301,6 +1301,7 @@ namespace qe { ptr_vector todo; todo.push_back(a); rational k1, k2; + expr* e1 = nullptr, *e2 = nullptr; expr_ref rest(m); while (!todo.empty()) { expr* e = todo.back(); @@ -1319,9 +1320,9 @@ namespace qe { return false; } a = to_app(e); - if (m_util.m_arith.is_mod(e) && - m_util.m_arith.is_numeral(to_app(e)->get_arg(1), k1) && - m_util.get_coeff(contains_x, to_app(e)->get_arg(0), k2, rest)) { + if (m_util.m_arith.is_mod(e, e1, e2) && + m_util.m_arith.is_numeral(e2, k1) && + m_util.get_coeff(contains_x, e1, k2, rest)) { app_ref z(m), z_bv(m); m_util.mk_bounded_var(k1, z_bv, z); m_nested_div_terms.push_back(rest); @@ -1331,10 +1332,9 @@ namespace qe { m_nested_div_z.push_back(z); continue; } - unsigned num_args = a->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { - todo.push_back(a->get_arg(i)); - } + for (expr* arg : *a) { + todo.push_back(arg); + } } return true; } diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index 714bf0e24..89776c479 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -43,7 +43,7 @@ def_module_params('sat', ('cardinality.solver', BOOL, True, 'use cardinality solver'), ('pb.solver', SYMBOL, 'solver', 'method for handling Pseudo-Boolean constraints: circuit (arithmetical circuit), sorting (sorting circuit), totalizer (use totalizer encoding), solver (use native solver)'), ('xor.solver', BOOL, False, 'use xor solver'), - ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-1 constraints grouped, bimander, ordered, unate, circuit'), + ('cardinality.encoding', SYMBOL, 'grouped', 'encoding used for at-most-k constraints: grouped, bimander, ordered, unate, circuit'), ('local_search', BOOL, False, 'use local search instead of CDCL'), ('local_search_threads', UINT, 0, 'number of local search threads to find satisfiable solution'), ('local_search_mode', SYMBOL, 'wsat', 'local search algorithm, either default wsat or qsat'), From c4e4139ab6e0bbd3ab1212bb0aa528e1ca73e8ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 21:33:53 -0700 Subject: [PATCH 020/118] fix clause check in goal2dimacs, redo rewriting of mod to avoid deeply nested mod Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 39 ++++++++++++++--------------- src/tactic/goal.cpp | 15 ++++++++--- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 7a03d84d7..ac2313266 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -927,30 +927,29 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul return BR_DONE; } - // propagate mod inside only if not all arguments are not already mod. + // propagate mod inside only if there is something to reduce. if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) { TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";); - unsigned num_args = to_app(arg1)->get_num_args(); - unsigned i; - rational arg_v; - for (i = 0; i < num_args; i++) { - expr * arg = to_app(arg1)->get_arg(i); - if (m_util.is_mod(arg)) - continue; - if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) == arg_v) - continue; - if (m().is_ite(arg)) - continue; - // found target for rewriting - break; + expr_ref_buffer args(m()); + bool change = false; + for (expr* arg : *to_app(arg1)) { + rational arg_v; + if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) != arg_v) { + change = true; + args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); + } + else if (m_util.is_mod(arg, t1, t2) && t2 == arg2) { + change = true; + args.push_back(t1); + } + else { + args.push_back(arg); + } } - TRACE("mod_bug", tout << "mk_mod target: " << i << "\n";); - if (i == num_args) + if (!change) { return BR_FAILED; // did not find any target for applying simplification - ptr_buffer new_args; - for (unsigned i = 0; i < num_args; i++) - new_args.push_back(m_util.mk_mod(to_app(arg1)->get_arg(i), arg2)); - result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), new_args.size(), new_args.c_ptr()), arg2); + } + result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.c_ptr()), arg2); TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m()) << "\n";); return BR_REWRITE3; } diff --git a/src/tactic/goal.cpp b/src/tactic/goal.cpp index f00f0e77e..dfe63e29a 100644 --- a/src/tactic/goal.cpp +++ b/src/tactic/goal.cpp @@ -721,11 +721,16 @@ bool goal::is_cnf() const { for (unsigned i = 0; i < size(); i++) { expr * f = form(i); if (m_manager.is_or(f)) { - for (expr* l : *to_app(f)) { - if (!is_literal(f)) return false; + for (expr* lit : *to_app(f)) { + if (!is_literal(lit)) { + return false; + } } + return true; + } + if (!is_literal(f)) { + return false; } - if (!is_literal(f)) return false; } return true; } @@ -735,7 +740,9 @@ bool goal::is_literal(expr* f) const { if (!is_app(f)) return false; if (to_app(f)->get_family_id() == m_manager.get_basic_family_id()) { for (expr* arg : *to_app(f)) - if (m_manager.is_bool(arg)) return false; + if (m_manager.is_bool(arg)) { + return false; + } } return true; } From dc932a93e24405a857296eaeaff844a416935a5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 21:44:16 -0700 Subject: [PATCH 021/118] fix #1736 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 60a9bd734..7711ec4cd 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -7241,11 +7241,13 @@ class Optimize(Z3PPObject): def assert_exprs(self, *args): """Assert constraints as background axioms for the optimize solver.""" args = _get_args(args) + s = BoolSort(self.ctx) for arg in args: if isinstance(arg, Goal) or isinstance(arg, AstVector): for f in arg: Z3_optimize_assert(self.ctx.ref(), self.optimize, f.as_ast()) else: + arg = s.cast(arg) Z3_optimize_assert(self.ctx.ref(), self.optimize, arg.as_ast()) def add(self, *args): From dfbd285daefb394741d5e5052f9c6fba1f6f3b04 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Jul 2018 22:02:48 -0700 Subject: [PATCH 022/118] avoid rewriting if reduces to tautology Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b105def2c..9315e75ac 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1373,8 +1373,10 @@ public: expr_ref atom1(m); proof_ref atomp(m); ctx().get_rewriter()(atom, atom1, atomp); - atom = to_app(atom1); - TRACE("arith", tout << atom << "\n"; + if (!m.is_false(atom1) && !m.is_true(atom1)) { + atom = to_app(atom1); + } + TRACE("arith", tout << t << ": " << atom << "\n"; m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n";); ctx().internalize(atom, true); ctx().mark_as_relevant(atom.get()); From 1de0f8fe5e8ffbd6643738a6c0ab7994f15eec94 Mon Sep 17 00:00:00 2001 From: Arie Gurfinkel Date: Sat, 7 Jul 2018 19:10:16 +0300 Subject: [PATCH 023/118] Fix bug in proof checking --- src/ast/proofs/proof_checker.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index fd6ea43e1..404551178 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -389,14 +389,14 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { match_fact(p, fact) && match_fact(p1, fml) && match_and(fml, terms)) { - for (expr* t : terms) + for (expr* t : terms) if (t == fact) return true; } UNREACHABLE(); return false; } case PR_NOT_OR_ELIM: { - + if (match_proof(p, p1) && match_fact(p, fact) && match_fact(p1, fml) && @@ -605,6 +605,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { bool found = false; for (expr* term2 : terms2) { found = term1 == term2; + if (found) break; } if (!found) { IF_VERBOSE(0, verbose_stream() << "Premise not found:" << mk_pp(term1, m) << "\n";); @@ -738,9 +739,9 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { } if (is_quantifier(e)) { SASSERT(!is_lambda(e)); - q = to_quantifier(e); + q = to_quantifier(e); // TBD check that quantifier is properly instantiated - return is_forall == ::is_forall(q); + return is_forall == ::is_forall(q); } } UNREACHABLE(); @@ -1004,7 +1005,7 @@ bool proof_checker::match_op(expr const* e, decl_kind k, ptr_vector& terms if (e->get_kind() == AST_APP && to_app(e)->get_family_id() == m.get_basic_family_id() && to_app(e)->get_decl_kind() == k) { - for (expr* arg : *to_app(e)) + for (expr* arg : *to_app(e)) terms.push_back(arg); return true; } From d2b77b11704b3efd3d8a9851c6a13f1e9863f135 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 7 Jul 2018 19:07:13 +0100 Subject: [PATCH 024/118] remove dead code --- src/tactic/smtlogics/qfbv_tactic.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/tactic/smtlogics/qfbv_tactic.cpp b/src/tactic/smtlogics/qfbv_tactic.cpp index bc93b4e7b..a8ad95319 100644 --- a/src/tactic/smtlogics/qfbv_tactic.cpp +++ b/src/tactic/smtlogics/qfbv_tactic.cpp @@ -89,14 +89,6 @@ static tactic * mk_qfbv_tactic(ast_manager& m, params_ref const & p, tactic* sat params_ref solver_p; solver_p.set_bool("preprocess", false); // preprocessor of smt::context is not needed. - params_ref no_flat_p; - no_flat_p.set_bool("flat", false); - - params_ref ctx_simp_p; - ctx_simp_p.set_uint("max_depth", 32); - ctx_simp_p.set_uint("max_steps", 50000000); - - params_ref big_aig_p; big_aig_p.set_bool("aig_per_assertion", false); From fd75eccfec8dcbefad560c978fcfcf5ca21a0721 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 8 Jul 2018 13:21:16 +0100 Subject: [PATCH 025/118] don't even bother allocating traces in release mode --- src/util/trace.cpp | 7 ++----- src/util/trace.h | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/util/trace.cpp b/src/util/trace.cpp index 9571e99e6..68437ab92 100644 --- a/src/util/trace.cpp +++ b/src/util/trace.cpp @@ -21,7 +21,6 @@ Revision History: #ifdef _TRACE std::ofstream tout(".z3-trace"); -#endif static bool g_enable_all_trace_tags = false; static str_hashtable* g_enabled_trace_tags = nullptr; @@ -56,13 +55,11 @@ bool is_trace_enabled(const char * tag) { } void close_trace() { -#ifdef _TRACE tout.close(); -#endif } void open_trace() { -#ifdef _TRACE tout.open(".z3-trace"); -#endif } + +#endif diff --git a/src/util/trace.h b/src/util/trace.h index 789beafc1..be652a620 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -33,9 +33,6 @@ Revision History: #ifdef _TRACE extern std::ofstream tout; #define TRACE_CODE(CODE) { CODE } ((void) 0 ) -#else -#define TRACE_CODE(CODE) ((void) 0) -#endif void enable_trace(const char * tag); void enable_all_trace(bool flag); @@ -48,6 +45,18 @@ void finalize_trace(); ADD_FINALIZER('finalize_trace();') */ +#else +#define TRACE_CODE(CODE) ((void) 0) + +static inline void enable_trace(const char * tag) {} +static inline void enable_all_trace(bool flag) {} +static inline void disable_trace(const char * tag) {} +static inline bool is_trace_enabled(const char * tag) {} +static inline void close_trace() {} +static inline void open_trace() {} +static inline void finalize_trace() {} +#endif + #define TRACE(TAG, CODE) TRACE_CODE(if (is_trace_enabled(TAG)) { tout << "-------- [" << TAG << "] " << __FUNCTION__ << " " << __FILE__ << ":" << __LINE__ << " ---------\n"; CODE tout << "------------------------------------------------\n"; tout.flush(); }) #define STRACE(TAG, CODE) TRACE_CODE(if (is_trace_enabled(TAG)) { CODE tout.flush(); }) @@ -55,4 +64,3 @@ void finalize_trace(); #define CTRACE(TAG, COND, CODE) TRACE_CODE(if (is_trace_enabled(TAG) && (COND)) { tout << "-------- [" << TAG << "] " << __FUNCTION__ << " " << __FILE__ << ":" << __LINE__ << " ---------\n"; CODE tout << "------------------------------------------------\n"; tout.flush(); }) #endif /* TRACE_H_ */ - From a85a4f41c71136eef3c9eab7baad3548a31116b6 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 8 Jul 2018 15:32:01 +0100 Subject: [PATCH 026/118] ast_exception: remove str copies --- src/ast/ast.cpp | 18 +++++++++--------- src/ast/ast.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index ac7ce156d..f164d6a4f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1057,7 +1057,7 @@ sort* basic_decl_plugin::join(sort* s1, sort* s2) { } std::ostringstream buffer; buffer << "Sorts " << mk_pp(s1, *m_manager) << " and " << mk_pp(s2, *m_manager) << " are incompatible"; - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } @@ -1086,7 +1086,7 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters if (domain[i] != domain[0]) { std::ostringstream buffer; buffer << "Sort mismatch between first argument and argument " << (i+1); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } } return m_manager->mk_func_decl(symbol("distinct"), arity, domain, m_bool_sort, info); @@ -1701,9 +1701,9 @@ ast * ast_manager::register_node_core(ast * n) { SASSERT(m_ast_table.contains(n)); if (is_func_decl(r) && to_func_decl(r)->get_range() != to_func_decl(n)->get_range()) { std::ostringstream buffer; - buffer << "Recycling of declaration for the same name '" << to_func_decl(r)->get_name().str().c_str() << "'" - << " and domain, but different range type is not permitted"; - throw ast_exception(buffer.str().c_str()); + buffer << "Recycling of declaration for the same name '" << to_func_decl(r)->get_name().str() + << "' and domain, but different range type is not permitted"; + throw ast_exception(buffer.str()); } deallocate_node(n, ::get_node_size(n)); return r; @@ -1992,7 +1992,7 @@ void ast_manager::check_sort(func_decl const * decl, unsigned num_args, expr * c buff << "invalid function application for " << decl->get_name() << ", "; buff << "sort mismatch on argument at position " << (i+1) << ", "; buff << "expected " << mk_pp(expected, m) << " but given " << mk_pp(given, m); - throw ast_exception(buff.str().c_str()); + throw ast_exception(buff.str()); } } } @@ -2008,7 +2008,7 @@ void ast_manager::check_sort(func_decl const * decl, unsigned num_args, expr * c buff << "invalid function application for " << decl->get_name() << ", "; buff << "sort mismatch on argument at position " << (i+1) << ", "; buff << "expected " << mk_pp(expected, m) << " but given " << mk_pp(given, m); - throw ast_exception(buff.str().c_str()); + throw ast_exception(buff.str()); } } } @@ -2170,7 +2170,7 @@ void ast_manager::check_args(func_decl* f, unsigned n, expr* const* es) { << " for function " << mk_pp(f,*this) << " supplied sort is " << mk_pp(actual_sort, *this); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } } } @@ -2194,7 +2194,7 @@ app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * ar std::ostringstream buffer; buffer << "Wrong number of arguments (" << num_args << ") passed to function " << mk_pp(decl, *this); - throw ast_exception(buffer.str().c_str()); + throw ast_exception(buffer.str()); } app * r = nullptr; if (num_args == 1 && decl->is_chainable() && decl->get_arity() == 2) { diff --git a/src/ast/ast.h b/src/ast/ast.h index aa8669def..7cd1dff93 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -69,7 +69,7 @@ class ast_manager; */ class ast_exception : public default_exception { public: - ast_exception(char const * msg):default_exception(msg) {} + ast_exception(std::string && msg) : default_exception(std::move(msg)) {} }; typedef int family_id; From c5a282dadbaa2149d5d2f339bfa2c5348e903507 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 8 Jul 2018 18:04:32 +0100 Subject: [PATCH 027/118] sat_allocator: align allocation size with page boundary to reduce memory consumption --- src/sat/sat_allocator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_allocator.h b/src/sat/sat_allocator.h index 06585ebed..e588c8478 100644 --- a/src/sat/sat_allocator.h +++ b/src/sat/sat_allocator.h @@ -23,7 +23,7 @@ Revision History: #include "util/machine.h" class sat_allocator { - static const unsigned CHUNK_SIZE = (1 << 16); + static const unsigned CHUNK_SIZE = (1 << 16) - sizeof(char*); static const unsigned SMALL_OBJ_SIZE = 512; static const unsigned MASK = ((1 << PTR_ALIGNMENT) - 1); static const unsigned NUM_FREE = 1 + (SMALL_OBJ_SIZE >> PTR_ALIGNMENT); From d6a3afd2a136de53856109b63716e528311b95b1 Mon Sep 17 00:00:00 2001 From: alexanderjsummers Date: Mon, 9 Jul 2018 11:30:24 +0200 Subject: [PATCH 028/118] Added return value to bool-typed function It seems that without this, the build fails with a default Visual C++ on Windows; see https://docs.microsoft.com/en-gb/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4716 Another option would be to add the #pragma directive mentioned there. --- src/util/trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/trace.h b/src/util/trace.h index be652a620..c0dc90f23 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -51,7 +51,8 @@ void finalize_trace(); static inline void enable_trace(const char * tag) {} static inline void enable_all_trace(bool flag) {} static inline void disable_trace(const char * tag) {} -static inline bool is_trace_enabled(const char * tag) {} +// On a default Visual C++ build on Windows, a non-void function either needs to return a value, or we have to add: #pragma warning(default:4716) +static inline bool is_trace_enabled(const char * tag) { return false; } static inline void close_trace() {} static inline void open_trace() {} static inline void finalize_trace() {} From 6f7271a5e8b292965c25f54712c5980f8eefb3ec Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 9 Jul 2018 10:37:26 +0100 Subject: [PATCH 029/118] remove virtual destructor from api::pmanager --- src/api/api_polynomial.cpp | 11 ----------- src/api/api_polynomial.h | 6 +++--- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 8c5fc99c9..93a23cb04 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -26,17 +26,6 @@ Notes: #include "util/scoped_timer.h" #include "ast/expr2var.h" -namespace api { - - pmanager::pmanager(reslimit& lim): - m_pm(lim, m_nm) { - } - - pmanager::~pmanager() { - } - -}; - extern "C" { Z3_ast_vector Z3_API Z3_polynomial_subresultants(Z3_context c, Z3_ast p, Z3_ast q, Z3_ast x) { diff --git a/src/api/api_polynomial.h b/src/api/api_polynomial.h index fbb1e7e13..a31f6c2b8 100644 --- a/src/api/api_polynomial.h +++ b/src/api/api_polynomial.h @@ -23,13 +23,13 @@ Notes: namespace api { - class pmanager { + class pmanager final { unsynch_mpz_manager m_nm; polynomial::manager m_pm; // TODO: add support for caching expressions -> polynomial and back public: - pmanager(reslimit& limx); - virtual ~pmanager(); + pmanager(reslimit& lim) : m_pm(lim, m_nm) {} + ~pmanager() {} polynomial::manager & pm() { return m_pm; } }; From 009708ed07c487f6ec031f6f4d47ad00fa459b80 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 9 Jul 2018 10:52:27 +0100 Subject: [PATCH 030/118] remove unneeded creation of tmp mpz_manager --- src/math/polynomial/algebraic_numbers.cpp | 20 ++++++++------------ src/util/mpq.h | 6 ++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 5811811fc..aa4fc5a39 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -2629,17 +2629,15 @@ namespace algebraic_numbers { } else if (a.is_basic()) { mpq const & v = basic_value(a); - scoped_mpz neg_n(qm()); + mpz neg_n; qm().set(neg_n, v.numerator()); qm().neg(neg_n); - unsynch_mpz_manager zmgr; - // FIXME: remove these copies - mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; + mpz coeffs[2] = { std::move(neg_n), qm().dup(v.denominator()) }; out << "("; upm().display(out, 2, coeffs, "#"); out << ", 1)"; // first root of the polynomial d*# - n - zmgr.del(coeffs[0]); - zmgr.del(coeffs[1]); + qm().del(coeffs[0]); + qm().del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); @@ -2679,17 +2677,15 @@ namespace algebraic_numbers { } else if (a.is_basic()) { mpq const & v = basic_value(a); - scoped_mpz neg_n(qm()); + mpz neg_n; qm().set(neg_n, v.numerator()); qm().neg(neg_n); - unsynch_mpz_manager zmgr; - // FIXME: remove these copies - mpz coeffs[2] = { zmgr.dup(neg_n.get()), zmgr.dup(v.denominator()) }; + mpz coeffs[2] = { std::move(neg_n), qm().dup(v.denominator()) }; out << "(root-obj "; upm().display_smt2(out, 2, coeffs, "x"); out << " 1)"; // first root of the polynomial d*# - n - zmgr.del(coeffs[0]); - zmgr.del(coeffs[1]); + qm().del(coeffs[0]); + qm().del(coeffs[1]); } else { algebraic_cell * c = a.to_algebraic(); diff --git a/src/util/mpq.h b/src/util/mpq.h index 1bccabc74..b7bdbf400 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -714,6 +714,12 @@ public: return temp; } + mpz dup(const mpz & source) { + mpz temp; + set(temp, source); + return temp; + } + void swap(mpz & a, mpz & b) { mpz_manager::swap(a, b); } void swap(mpq & a, mpq & b) { From 605dcc40a3f0908a7da8bf2815736099334a48cf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jul 2018 09:19:13 -0700 Subject: [PATCH 031/118] fix #1741 Signed-off-by: Nikolaj Bjorner --- src/api/java/Optimize.java | 17 ++++++ src/ast/proofs/proof_checker.cpp | 2 +- src/ast/rewriter/arith_rewriter.cpp | 22 ++++++++ src/smt/theory_lra.cpp | 86 +++++++++++++++++++++++++---- src/util/sorting_network.h | 7 ++- 5 files changed, 121 insertions(+), 13 deletions(-) diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index a434b6e9f..c5f8f9449 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -314,6 +314,23 @@ public class Optimize extends Z3Object { Native.optimizeFromString(getContext().nCtx(), getNativeObject(), s); } + /** + * The set of asserted formulas. + */ + public BoolExpr[] getAssertions() + { + ASTVector assertions = new ASTVector(getContext(), Native.optimizeGetAssertions(getContext().nCtx(), getNativeObject())); + return assertions.ToBoolExprArray(); + } + + /** + * The set of asserted formulas. + */ + public Expr[] getObjectives() + { + ASTVector objectives = new ASTVector(getContext(), Native.optimizeGetObjectives(getContext().nCtx(), getNativeObject())); + return objectives.ToExprArray(); + } /** * Optimize statistics. diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index fd6ea43e1..448c14fe3 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -192,7 +192,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { expr* t1 = nullptr, *t2 = nullptr; expr* s1 = nullptr, *s2 = nullptr; expr* u1 = nullptr, *u2 = nullptr; - expr* fact = nullptr, *body1 = nullptr, *body2 = nullptr; + expr* fact = nullptr, *body1 = nullptr; expr* l1 = nullptr, *l2 = nullptr, *r1 = nullptr, *r2 = nullptr; func_decl* d1 = nullptr, *d2 = nullptr, *d3 = nullptr; proof* p0 = nullptr, *p1 = nullptr, *p2 = nullptr; diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index ac2313266..6ddce9b80 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -812,6 +812,28 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); return BR_REWRITE3; } + if (m_util.is_numeral(arg2, v2, is_int) && v2.is_pos() && m_util.is_add(arg1)) { + expr_ref_buffer args(m()); + bool change = false; + rational add(0); + for (expr* arg : *to_app(arg1)) { + rational arg_v; + if (m_util.is_numeral(arg, arg_v) && arg_v.is_pos() && mod(arg_v, v2) != arg_v) { + change = true; + args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); + add += div(arg_v, v2); + } + else { + args.push_back(arg); + } + } + if (change) { + result = m_util.mk_idiv(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.c_ptr()), arg2); + result = m_util.mk_add(m_util.mk_numeral(add, true), result); + TRACE("div_bug", tout << "mk_div result: " << result << "\n";); + return BR_REWRITE3; + } + } if (divides(arg1, arg2, result)) { return BR_REWRITE_FULL; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 9315e75ac..17c850330 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1362,22 +1362,46 @@ public: // create a bound atom representing term >= k is lower_bound is true, and term <= k if it is false app_ref mk_bound(lp::lar_term const& term, rational const& k, bool lower_bound) { - app_ref t = mk_term(term, k.is_int()); + bool is_int = k.is_int(); + rational offset = -k; + u_map coeffs; + term2coeffs(term, coeffs, rational::one(), offset); + offset.neg(); + if (is_int) { + // 3x + 6y >= 5 -> x + 3y >= 5/3, then x + 3y >= 2 + // 3x + 6y <= 5 -> x + 3y <= 1 + + rational g = gcd_reduce(coeffs); + if (!g.is_one()) { + if (lower_bound) { + offset = div(offset + g - rational::one(), g); + } + else { + offset = div(offset, g); + } + } + } + app_ref atom(m); + app_ref t = coeffs2app(coeffs, rational::zero(), is_int); if (lower_bound) { - atom = a.mk_ge(t, a.mk_numeral(k, k.is_int())); + atom = a.mk_ge(t, a.mk_numeral(offset, is_int)); } else { - atom = a.mk_le(t, a.mk_numeral(k, k.is_int())); + atom = a.mk_le(t, a.mk_numeral(offset, is_int)); } + + +#if 0 expr_ref atom1(m); proof_ref atomp(m); ctx().get_rewriter()(atom, atom1, atomp); if (!m.is_false(atom1) && !m.is_true(atom1)) { atom = to_app(atom1); } +#endif TRACE("arith", tout << t << ": " << atom << "\n"; - m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n";); + m_solver->print_term(term, tout << "bound atom: "); tout << (lower_bound?" <= ":" >= ") << k << "\n";); ctx().internalize(atom, true); ctx().mark_as_relevant(atom.get()); return atom; @@ -1396,6 +1420,7 @@ public: case lp::lia_move::sat: return l_true; case lp::lia_move::branch: { + TRACE("arith", tout << "branch\n";); app_ref b = mk_bound(term, k, !upper); // branch on term >= k + 1 // branch on term <= k @@ -1405,6 +1430,7 @@ public: return l_false; } case lp::lia_move::cut: { + TRACE("arith", tout << "cutn";); ++m_stats.m_gomory_cuts; // m_explanation implies term <= k app_ref b = mk_bound(term, k, !upper); @@ -2809,26 +2835,44 @@ public: return internalize_def(term); } - app_ref mk_term(lp::lar_term const& term, bool is_int) { - expr_ref_vector args(m); + void term2coeffs(lp::lar_term const& term, u_map& coeffs, rational const& coeff, rational& offset) { for (const auto & ti : term) { theory_var w; if (m_solver->is_term(ti.var())) { - w = m_term_index2theory_var[m_solver->adjust_term_index(ti.var())]; + //w = m_term_index2theory_var.get(m_solver->adjust_term_index(ti.var()), null_theory_var); + //if (w == null_theory_var) // if extracing expressions directly from nested term + lp::lar_term const& term1 = m_solver->get_term(ti.var()); + rational coeff2 = coeff * ti.coeff(); + term2coeffs(term1, coeffs, coeff2, offset); + continue; } else { w = m_var_index2theory_var[ti.var()]; } + rational c0(0); + coeffs.find(w, c0); + coeffs.insert(w, c0 + ti.coeff() * coeff); + } + offset += coeff * term.m_v; + } + + app_ref coeffs2app(u_map const& coeffs, rational const& offset, bool is_int) { + expr_ref_vector args(m); + for (auto const& kv : coeffs) { + theory_var w = kv.m_key; expr* o = get_enode(w)->get_owner(); - if (ti.coeff().is_one()) { + if (kv.m_value.is_zero()) { + // continue + } + else if (kv.m_value.is_one()) { args.push_back(o); } else { - args.push_back(a.mk_mul(a.mk_numeral(ti.coeff(), is_int), o)); + args.push_back(a.mk_mul(a.mk_numeral(kv.m_value, is_int), o)); } } - if (!term.m_v.is_zero()) { - args.push_back(a.mk_numeral(term.m_v, is_int)); + if (!offset.is_zero()) { + args.push_back(a.mk_numeral(offset, is_int)); } switch (args.size()) { case 0: @@ -2840,6 +2884,26 @@ public: } } + app_ref mk_term(lp::lar_term const& term, bool is_int) { + u_map coeffs; + rational offset; + term2coeffs(term, coeffs, rational::one(), offset); + return coeffs2app(coeffs, offset, is_int); + } + + rational gcd_reduce(u_map& coeffs) { + rational g(0); + for (auto const& kv : coeffs) { + g = gcd(g, kv.m_value); + } + if (!g.is_one() && !g.is_zero()) { + for (auto& kv : coeffs) { + kv.m_value /= g; + } + } + return g; + } + app_ref mk_obj(theory_var v) { lp::var_index vi = m_theory_var2var_index[v]; bool is_int = a.is_int(get_enode(v)->get_owner()); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index d7d8e8bbe..ff083162d 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -977,6 +977,7 @@ Notes: unsigned b, literal const* bs, literal_vector& out) { unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; if (a == 1 && b == 1) { literal y1 = mk_max(as[0], bs[0]); literal y2 = mk_min(as[0], bs[0]); @@ -1054,6 +1055,7 @@ Notes: literal_vector const& bs, literal_vector& out) { unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; SASSERT(as.size() >= bs.size()); SASSERT(as.size() <= bs.size() + 2); SASSERT(!as.empty()); @@ -1152,6 +1154,7 @@ Notes: unsigned b, literal const* bs, literal_vector& out) { unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; if (a == 1 && b == 1 && c == 1) { literal y = mk_max(as[0], bs[0]); if (m_t != GE) { @@ -1270,7 +1273,8 @@ Notes: unsigned a, literal const* as, unsigned b, literal const* bs, literal_vector& out) { - unsigned nc = m_stats.m_num_compiled_clauses; + unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; SASSERT(a <= c); SASSERT(b <= c); SASSERT(a + b >= c); @@ -1338,6 +1342,7 @@ Notes: SASSERT(m <= n); literal_vector lits; unsigned nc = m_stats.m_num_compiled_clauses; + (void)nc; for (unsigned i = 0; i < m; ++i) { out.push_back(fresh("dsort")); } From 8373bec6ad0bc2c91bd09319ad187fd7f7821e17 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jul 2018 10:33:56 -0700 Subject: [PATCH 032/118] only assign, if there isn't already a true literal incube/clause mode Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 70b55acee..be4e8321f 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3186,6 +3186,7 @@ namespace smt { if (m_tmp_clauses.empty()) return l_true; for (auto & tmp_clause : m_tmp_clauses) { literal_vector& lits = tmp_clause.second; + literal unassigned = null_literal; for (literal l : lits) { switch (get_assignment(l)) { case l_false: @@ -3193,13 +3194,17 @@ namespace smt { case l_true: goto next_clause; default: - shuffle(lits.size(), lits.c_ptr(), m_random); - push_scope(); - assign(l, b_justification::mk_axiom(), true); - return l_undef; + unassigned = l; } } + if (unassigned != null_literal) { + shuffle(lits.size(), lits.c_ptr(), m_random); + push_scope(); + assign(unassigned, b_justification::mk_axiom(), true); + return l_undef; + } + if (lits.size() == 1) { set_conflict(b_justification(), ~lits[0]); } From de454db58c1846c6c7b4596e6131f161277b2444 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jul 2018 14:17:39 -0700 Subject: [PATCH 033/118] guard expensive ite rewrites under configuration Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 30 +++++++++++++++------------- src/math/simplex/model_based_opt.cpp | 4 +++- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index d61c906be..d26c55fda 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -613,12 +613,12 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) expr* cond2 = nullptr, *t2 = nullptr, *e2 = nullptr; if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(t), val, result); + VERIFY(BR_FAILED != try_ite_value(to_app(t), val, result)); result = m().mk_ite(cond, result, m().mk_eq(e, val)); return BR_REWRITE2; } if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) { - try_ite_value(to_app(e), val, result); + VERIFY(BR_FAILED != try_ite_value(to_app(e), val, result)); result = m().mk_ite(cond, m().mk_eq(t, val), result); return BR_REWRITE2; } @@ -640,19 +640,21 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { br_status r = BR_FAILED; - if (m().is_ite(lhs) && m().is_value(rhs)) { - r = try_ite_value(to_app(lhs), to_app(rhs), result); - CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + + if (m_ite_extra_rules) { + if (m().is_ite(lhs) && m().is_value(rhs)) { + r = try_ite_value(to_app(lhs), to_app(rhs), result); + CTRACE("try_ite_value", r != BR_FAILED, + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + } + else if (m().is_ite(rhs) && m().is_value(lhs)) { + r = try_ite_value(to_app(rhs), to_app(lhs), result); + CTRACE("try_ite_value", r != BR_FAILED, + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); + } + if (r != BR_FAILED) + return r; } - else if (m().is_ite(rhs) && m().is_value(lhs)) { - r = try_ite_value(to_app(rhs), to_app(lhs), result); - CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); - } - if (r != BR_FAILED) - return r; - if (m().is_bool(lhs)) { bool unfolded = false; diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index d1bb90f0c..d3e780d33 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -1085,7 +1085,7 @@ namespace opt { if (D.is_zero()) { throw default_exception("modulo 0 is not defined"); } - TRACE("opt", display(tout << "lcm: " << D << " tableau\n");); + TRACE("opt1", display(tout << "lcm: " << D << " x: v" << x << " tableau\n");); rational val_x = m_var2value[x]; rational u = mod(val_x, D); SASSERT(u.is_nonneg() && u < D); @@ -1093,6 +1093,7 @@ namespace opt { replace_var(idx, x, u); SASSERT(invariant(idx, m_rows[idx])); } + TRACE("opt1", display(tout << "tableau after replace x under mod\n");); // // update inequalities such that u is added to t and // D is multiplied to coefficient of x. @@ -1114,6 +1115,7 @@ namespace opt { visited.insert(row_id); } } + TRACE("opt1", display(tout << "tableau after replace x by y := v" << y << "\n");); def result = project(y, compute_def); if (compute_def) { result = (result * D) + u; From 567fbac27f0f4ee2b90f4746f457de9173196280 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jul 2018 14:33:32 -0700 Subject: [PATCH 034/118] add back old multiplication for comparison Signed-off-by: Nikolaj Bjorner --- src/util/mpq.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index 4c636f1af..30ac0f410 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -346,6 +346,7 @@ void mpq_manager::lin_arith_op(mpq const& a, mpq const& b, mpq& c, mpz& g template void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, mpz& g2, mpz& tmp1, mpz& tmp2) { +#if 1 gcd(a.m_den, b.m_num, g1); gcd(a.m_num, b.m_den, g2); div(a.m_num, g2, tmp1); @@ -354,6 +355,11 @@ void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c, mpz& g1, div(b.m_den, g2, tmp1); div(a.m_den, g1, tmp2); mul(tmp1, tmp2, c.m_den); +#else + mul(a.m_num, b.m_num, c.m_num); + mul(a.m_den, b.m_den, c.m_den); + normalize(c); +#endif } template From fc4627a24f44a5431d6a4677b75949def80a4814 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Jul 2018 16:33:48 -0700 Subject: [PATCH 035/118] force the new arithmetic solver for QF_LIA Signed-off-by: Nikolaj Bjorner --- src/math/simplex/model_based_opt.cpp | 11 ++++++++--- src/smt/smt_setup.cpp | 6 +++++- src/tactic/smtlogics/qflia_tactic.cpp | 9 +-------- src/util/sorting_network.h | 2 -- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index d3e780d33..8a771e07c 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -166,7 +166,7 @@ namespace opt { return true; } -#define PASSERT(_e_) if (!(_e_)) { TRACE("opt", display(tout, r);); SASSERT(_e_); } +#define PASSERT(_e_) if (!(_e_)) { TRACE("opt1", display(tout, r); display(tout);); SASSERT(_e_); } bool model_based_opt::invariant(unsigned index, row const& r) { vector const& vars = r.m_vars; @@ -539,7 +539,7 @@ namespace opt { rational slack = (abs_src_c - rational::one()) * (abs_dst_c - rational::one()); rational dst_val = dst.m_value - x_val*dst_c; rational src_val = src.m_value - x_val*src_c; - rational distance = src_c * dst_val + dst_c * src_val + slack; + rational distance = abs_src_c * dst_val + abs_dst_c * src_val + slack; bool use_case1 = distance.is_nonpos() || abs_src_c.is_one() || abs_dst_c.is_one(); #if 0 @@ -655,7 +655,10 @@ namespace opt { void model_based_opt::normalize(unsigned row_id) { row& r = m_rows[row_id]; - if (r.m_vars.empty()) return; + if (r.m_vars.empty()) { + retire_row(row_id); + return; + } if (r.m_type == t_mod) return; rational g(abs(r.m_vars[0].m_coeff)); bool all_int = g.is_int(); @@ -1092,6 +1095,7 @@ namespace opt { for (unsigned idx : mod_rows) { replace_var(idx, x, u); SASSERT(invariant(idx, m_rows[idx])); + normalize(idx); } TRACE("opt1", display(tout << "tableau after replace x under mod\n");); // @@ -1113,6 +1117,7 @@ namespace opt { // x |-> D*y + u replace_var(row_id, x, D, y, u); visited.insert(row_id); + normalize(row_id); } } TRACE("opt1", display(tout << "tableau after replace x by y := v" << y << "\n");); diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index ca3c01189..a85e95b57 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -777,7 +777,11 @@ namespace smt { IF_VERBOSE(1000, st.display_primitive(verbose_stream());); bool fixnum = st.arith_k_sum_is_small() && m_params.m_arith_fixnum; bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; - switch(m_params.m_arith_mode) { + auto mode = m_params.m_arith_mode; + if (m_logic == "QF_LIA") { + mode = AS_NEW_ARITH; + } + switch(mode) { case AS_NO_ARITH: m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); break; diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index 46b766bd4..eed4e4425 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -60,6 +60,7 @@ probe * mk_is_quasi_pb_probe() { // Create SMT solver that does not use cuts static tactic * mk_no_cut_smt_tactic(unsigned rs) { params_ref solver_p; + solver_p.set_sym(symbol("smt.logic"), symbol("QF_LIA")); // force smt_setup to use the new solver solver_p.set_uint("arith.branch_cut_ratio", 10000000); solver_p.set_uint("random_seed", rs); return annotate_tactic("no-cut-smt-tactic", using_params(mk_smt_tactic_using(false), solver_p)); @@ -209,15 +210,8 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { params_ref quasi_pb_p; quasi_pb_p.set_uint("lia2pb_max_bits", 64); - params_ref no_cut_p; - no_cut_p.set_uint("arith.branch_cut_ratio", 10000000); - - tactic * st = using_params(and_then(preamble_st, -#if 0 - mk_smt_tactic()), -#else or_else(mk_ilp_model_finder_tactic(m), mk_pb_tactic(m), and_then(fail_if_not(mk_is_quasi_pb_probe()), @@ -225,7 +219,6 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), mk_smt_tactic())), -#endif main_p); diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index ff083162d..b094a5b66 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -366,8 +366,6 @@ Notes: if (cmp == LE || cmp == EQ || cmp == LE_FULL) { last = k + 1; } - bool full = cmp == LE_FULL || cmp == GE_FULL; - literal_vector carry; for (unsigned i = 0; i < last; ++i) { carry.push_back(ctx.mk_false()); From bb534f61036e67bc9c29ade178722005dc818464 Mon Sep 17 00:00:00 2001 From: rainoftime Date: Tue, 10 Jul 2018 11:16:20 +0800 Subject: [PATCH 036/118] Add example of using z3's model construction C++ API --- examples/c++/example.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 704756072..6faeb3edc 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -1155,6 +1155,30 @@ static void parse_example() { // expr b = c.parse_string("(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))"); } +void mk_model_example() { + context c; + + // construct empty model + model m(c); + + // create constants "a", "b" and get their func_decl + expr a = c.int_const("a"); + expr b = c.int_const("b"); + func_decl a_decl = a.decl(); + func_decl b_decl = b.decl(); + + // create numerals to be used in model + expr zero_numeral = c.int_val(0); + expr one_numeral = c.int_val(1); + + // add assignment to model + m.add_const_interp(a_decl, zero_numeral); + m.add_const_interp(b_decl, one_numeral); + + // evaluate a + b < 2 in the model + std::cout << m.eval(a + b < 2)<< std::endl; +} + int main() { @@ -1202,6 +1226,7 @@ int main() { sudoku_example(); std::cout << "\n"; consequence_example(); std::cout << "\n"; parse_example(); std::cout << "\n"; + mk_model_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { From 367fff618d164bb36ee5dba5b153565813d62b0d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Jul 2018 12:01:12 -0700 Subject: [PATCH 037/118] setting smt.arith.solver=6 by default Signed-off-by: Lev Nachmanson --- src/smt/params/smt_params_helper.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 3f4105c34..c39b74722 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -40,7 +40,7 @@ def_module_params(module_name='smt', ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), - ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), + ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), ('arith.nl.gb', BOOL, True, 'groebner Basis computation, this option is ignored when arith.nl=false'), ('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'), From fd980952eaeb675b9d00e206c9969b11b8e43a68 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 6 Jul 2018 10:53:04 -0700 Subject: [PATCH 038/118] rebase Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 17c850330..42132abba 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1168,9 +1168,8 @@ public: if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - if(!m_solver->is_term(vi)) - return rational::zero(); - + if (!m_solver->is_term(vi)) + return rational::zero(); m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { From c518ddac6f5f387035f493de3662fdfe77bc4eff Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 6 Jul 2018 11:13:38 -0700 Subject: [PATCH 039/118] rebase Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 42132abba..17c850330 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1168,8 +1168,9 @@ public: if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - if (!m_solver->is_term(vi)) - return rational::zero(); + if(!m_solver->is_term(vi)) + return rational::zero(); + m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { From 5c712d471f11d93fb88fd4e83b674dbd1ecf1a94 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 7 Jul 2018 16:18:42 -0700 Subject: [PATCH 040/118] create hnf cuts too, when gomory_cut_period is 2 Signed-off-by: Lev Nachmanson --- src/smt/params/smt_params_helper.pyg | 2 +- src/util/lp/int_solver.cpp | 2 +- src/util/lp/lar_solver.cpp | 12 ++++++------ src/util/lp/lp_settings.h | 5 +++++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index c39b74722..3f4105c34 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -40,7 +40,7 @@ def_module_params(module_name='smt', ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), - ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), + ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), ('arith.nl.gb', BOOL, True, 'groebner Basis computation, this option is ignored when arith.nl=false'), ('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'), diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 0691b5887..f49ecabfd 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -599,7 +599,7 @@ lia_move int_solver::make_hnf_cut() { } lia_move int_solver::hnf_cut() { - if ((m_number_of_calls) % settings().m_hnf_cut_period == 0) { + if ((m_number_of_calls) % settings().hnf_cut_period() == 0) { return make_hnf_cut(); } return lia_move::undef; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 6fec5b329..2cf0c214d 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2263,16 +2263,16 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term } void lar_solver::set_cut_strategy(unsigned cut_frequency) { - if (cut_frequency < 4) { // enable only gomory cut - settings().m_int_gomory_cut_period = 2; - settings().m_hnf_cut_period = 100000000; + if (cut_frequency < 4) { + settings().m_int_gomory_cut_period = 2; // do it often + settings().set_hnf_cut_period(4); // also create hnf cuts } else if (cut_frequency == 4) { // enable all cuts and cube equally settings().m_int_gomory_cut_period = 4; - settings().m_hnf_cut_period = 4; + settings().set_hnf_cut_period(4); } else { - // disable all heuristics + // disable all heuristics except cube settings().m_int_gomory_cut_period = 10000000; - settings().m_hnf_cut_period = 100000000; + settings().set_hnf_cut_period(100000000); } } diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index b2e785064..4e99ecc82 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -189,13 +189,18 @@ public: unsigned column_number_threshold_for_using_lu_in_lar_solver; unsigned m_int_gomory_cut_period; unsigned m_int_find_cube_period; +private: unsigned m_hnf_cut_period; +public: bool m_int_run_gcd_test; bool m_int_pivot_fixed_vars_from_basis; bool m_int_patch_only_integer_values; unsigned limit_on_rows_for_hnf_cutter; unsigned limit_on_columns_for_hnf_cutter; + + unsigned hnf_cut_period() const { return m_hnf_cut_period; } + void set_hnf_cut_period(unsigned period) { m_hnf_cut_period = period; } unsigned random_next() { return m_rand(); } void set_random_seed(unsigned s) { m_rand.set_seed(s); } From c4c52ad104e53a987d347d76d42f9f5277e3761b Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 9 Jul 2018 20:48:39 -0700 Subject: [PATCH 041/118] enable printing in Release Signed-off-by: Lev --- src/util/lp/binary_heap_priority_queue.h | 2 -- src/util/lp/binary_heap_priority_queue_def.h | 2 -- src/util/lp/general_matrix.h | 3 --- src/util/lp/indexed_vector.cpp | 2 +- src/util/lp/indexed_vector.h | 2 +- src/util/lp/indexed_vector_def.h | 2 +- src/util/lp/lu.cpp | 2 +- src/util/lp/lu.h | 3 --- src/util/lp/lu_def.h | 4 ---- src/util/lp/matrix.cpp | 8 ++++---- src/util/lp/matrix.h | 2 -- src/util/lp/matrix_def.h | 5 ++--- src/util/lp/square_sparse_matrix.h | 6 ------ 13 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/util/lp/binary_heap_priority_queue.h b/src/util/lp/binary_heap_priority_queue.h index 9a71fc01e..018d154ab 100644 --- a/src/util/lp/binary_heap_priority_queue.h +++ b/src/util/lp/binary_heap_priority_queue.h @@ -78,8 +78,6 @@ public: lp_assert(m_heap_size > 0); return m_heap[1]; } -#ifdef Z3DEBUG void print(std::ostream & out); -#endif }; } diff --git a/src/util/lp/binary_heap_priority_queue_def.h b/src/util/lp/binary_heap_priority_queue_def.h index 8a39ecdfa..232959c83 100644 --- a/src/util/lp/binary_heap_priority_queue_def.h +++ b/src/util/lp/binary_heap_priority_queue_def.h @@ -194,7 +194,6 @@ template unsigned binary_heap_priority_queue::dequeue() { m_heap_inverse[ret] = -1; return ret; } -#ifdef Z3DEBUG template void binary_heap_priority_queue::print(std::ostream & out) { vector index; vector prs; @@ -210,5 +209,4 @@ template void binary_heap_priority_queue::print(std::ostream & o for (int i = 0; i < index.size(); i++) enqueue(index[i], prs[i]); } -#endif } diff --git a/src/util/lp/general_matrix.h b/src/util/lp/general_matrix.h index 715f2cb08..ce510eb6e 100644 --- a/src/util/lp/general_matrix.h +++ b/src/util/lp/general_matrix.h @@ -71,7 +71,6 @@ public: ref_row operator[](unsigned i) { return ref_row(*this, m_data[adjust_row(i)]); } ref_row_const operator[](unsigned i) const { return ref_row_const(*this, m_data[adjust_row(i)]); } -#ifdef Z3DEBUG void print(std::ostream & out, unsigned blanks = 0) const { unsigned m = row_count(); unsigned n = column_count(); @@ -96,8 +95,6 @@ public: print_matrix(m.m_data, out, blanks); } -#endif - void clear() { m_data.clear(); } bool row_is_initialized_correctly(const vector& row) { diff --git a/src/util/lp/indexed_vector.cpp b/src/util/lp/indexed_vector.cpp index 180291705..11378f151 100644 --- a/src/util/lp/indexed_vector.cpp +++ b/src/util/lp/indexed_vector.cpp @@ -37,10 +37,10 @@ template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector::is_OK() const; template bool indexed_vector >::is_OK() const; +#endif template void lp::indexed_vector< lp::mpq>::print(std::basic_ostream > &); template void lp::indexed_vector::print(std::basic_ostream > &); template void lp::indexed_vector >::print(std::ostream&); -#endif } // template void lp::print_vector(vector const&, std::ostream&); // template void lp::print_vector(vector const&, std::ostream&); diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index d6ff4e76a..d472a4a1e 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -216,7 +216,7 @@ public: #ifdef Z3DEBUG bool is_OK() const; - void print(std::ostream & out); #endif + void print(std::ostream & out); }; } diff --git a/src/util/lp/indexed_vector_def.h b/src/util/lp/indexed_vector_def.h index 2f7706089..a133eb379 100644 --- a/src/util/lp/indexed_vector_def.h +++ b/src/util/lp/indexed_vector_def.h @@ -96,6 +96,7 @@ bool indexed_vector::is_OK() const { return true; } +#endif template void indexed_vector::print(std::ostream & out) { out << "m_index " << std::endl; @@ -105,6 +106,5 @@ void indexed_vector::print(std::ostream & out) { out << std::endl; print_vector(m_data, out); } -#endif } diff --git a/src/util/lp/lu.cpp b/src/util/lp/lu.cpp index e6df10908..ac29dd71a 100644 --- a/src/util/lp/lu.cpp +++ b/src/util/lp/lu.cpp @@ -42,11 +42,11 @@ template void init_factorization> template void init_factorization> (lu>*&, static_matrix&, vector&, lp_settings&); template void init_factorization>(lu >*&, static_matrix&, vector&, lp_settings&); -#ifdef Z3DEBUG template void print_matrix>(square_sparse_matrix&, std::ostream & out); template void print_matrix>(static_matrix&, std::ostream&); template void print_matrix >(static_matrix&, std::ostream&); template void print_matrix>(static_matrix&, std::ostream & out); +#ifdef Z3DEBUG template bool lu>::is_correct(const vector& basis); template bool lu>::is_correct( vector const &); template dense_matrix get_B>(lu>&, const vector& basis); diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 820786d87..3b5a9cc59 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -39,15 +39,12 @@ Revision History: #include "util/lp/square_dense_submatrix.h" #include "util/lp/dense_matrix.h" namespace lp { -#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc); template void print_matrix(M &m, std::ostream & out); -#endif - template X dot_product(const vector & a, const vector & b) { lp_assert(a.size() == b.size()); diff --git a/src/util/lp/lu_def.h b/src/util/lp/lu_def.h index be4cd724d..51f291e7e 100644 --- a/src/util/lp/lu_def.h +++ b/src/util/lp/lu_def.h @@ -25,7 +25,6 @@ Revision History: #include "util/debug.h" #include "util/lp/lu.h" namespace lp { -#ifdef Z3DEBUG template // print the nr x nc submatrix at the top left corner void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc, std::ostream & out) { vector> A; @@ -62,9 +61,6 @@ void print_matrix(M &m, std::ostream & out) { print_matrix_with_widths(A, widths, out); } -#endif - - template one_elem_on_diag::one_elem_on_diag(const one_elem_on_diag & o) { m_i = o.m_i; diff --git a/src/util/lp/matrix.cpp b/src/util/lp/matrix.cpp index 2fb064111..7d3fba08d 100644 --- a/src/util/lp/matrix.cpp +++ b/src/util/lp/matrix.cpp @@ -18,14 +18,14 @@ Revision History: --*/ #include "util/lp/lp_settings.h" -#ifdef Z3DEBUG #include "util/lp/matrix_def.h" #include "util/lp/static_matrix.h" #include -template void lp::print_matrix(lp::matrix const*, std::ostream & out); +#ifdef Z3DEBUG template bool lp::matrix::is_equal(lp::matrix const&); -template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); -template void lp::print_matrix(lp::matrix const*, std::ostream&); template bool lp::matrix >::is_equal(lp::matrix > const&); template bool lp::matrix::is_equal(lp::matrix const&); #endif +template void lp::print_matrix(lp::matrix const*, std::ostream & out); +template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); +template void lp::print_matrix(lp::matrix const*, std::ostream&); diff --git a/src/util/lp/matrix.h b/src/util/lp/matrix.h index 063513287..8b2fc4220 100644 --- a/src/util/lp/matrix.h +++ b/src/util/lp/matrix.h @@ -17,7 +17,6 @@ Revision History: --*/ -#ifdef Z3DEBUG #pragma once #include "util/lp/numeric_pair.h" #include "util/vector.h" @@ -70,4 +69,3 @@ void print_matrix(const vector> & A, std::ostream & out, unsigned blan } -#endif diff --git a/src/util/lp/matrix_def.h b/src/util/lp/matrix_def.h index ae5f05ad1..361540cae 100644 --- a/src/util/lp/matrix_def.h +++ b/src/util/lp/matrix_def.h @@ -18,11 +18,11 @@ Revision History: --*/ -#ifdef Z3DEBUG #include #include #include "util/lp/matrix.h" namespace lp { +#ifdef Z3DEBUG template bool matrix::is_equal(const matrix& other) { if (other.row_count() != row_count() || other.column_count() != column_count()) @@ -67,7 +67,7 @@ void apply_to_vector(matrix & m, T * w) { delete [] wc; } - +#endif unsigned get_width_of_column(unsigned j, vector> & A) { unsigned r = 0; @@ -132,4 +132,3 @@ void print_matrix(matrix const * m, std::ostream & out) { } } -#endif diff --git a/src/util/lp/square_sparse_matrix.h b/src/util/lp/square_sparse_matrix.h index d84a8a289..cb5193b2d 100644 --- a/src/util/lp/square_sparse_matrix.h +++ b/src/util/lp/square_sparse_matrix.h @@ -40,9 +40,7 @@ namespace lp { // it is a square matrix template class square_sparse_matrix -#ifdef Z3DEBUG : public matrix -#endif { struct col_header { unsigned m_shortened_markovitz; @@ -173,10 +171,8 @@ public: unsigned dimension() const {return static_cast(m_row_permutation.size());} -#ifdef Z3DEBUG unsigned row_count() const override {return dimension();} unsigned column_count() const override {return dimension();} -#endif void init_row_headers(); @@ -309,13 +305,11 @@ public: template void solve_U_y_indexed_only(indexed_vector & y, const lp_settings&, vector & sorted_active_rows ); -#ifdef Z3DEBUG T get_elem(unsigned i, unsigned j) const override { return get(i, j); } unsigned get_number_of_rows() const { return dimension(); } unsigned get_number_of_columns() const { return dimension(); } void set_number_of_rows(unsigned /*m*/) override { } void set_number_of_columns(unsigned /*n*/) override { } -#endif template L dot_product_with_row (unsigned row, const vector & y) const; From b59fa3ebd7213ed94a1db489edd2013109981269 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jul 2018 09:05:24 -0700 Subject: [PATCH 042/118] fix #1746 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 6ddce9b80..8035254b4 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -936,9 +936,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul } if (arg1 == arg2 && !m_util.is_numeral(arg2)) { - expr_ref zero(m_util.mk_int(0), m()), abs(m()); - mk_abs_core(arg2, abs); - result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), abs); + expr_ref zero(m_util.mk_int(0), m()); + result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); return BR_DONE; } From a4a468660ddd4c6fe1436f6224e06e426096068f Mon Sep 17 00:00:00 2001 From: Lev Date: Tue, 10 Jul 2018 12:05:23 -0700 Subject: [PATCH 043/118] remove an assert Signed-off-by: Lev --- src/test/lp/lp.cpp | 1 - src/util/lp/hnf_cutter.h | 3 +-- src/util/lp/lar_solver.cpp | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index e5375a0df..6e418fe68 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -320,7 +320,6 @@ void test_small_lu(lp_settings & settings) { auto columns_to_replace = l.get_set_of_columns_to_replace_for_add_last_rows(heading); l.add_last_rows_to_B(heading, columns_to_replace); - std::cout << "here" << std::endl; lp_assert(l.is_correct(basis)); } diff --git a/src/util/lp/hnf_cutter.h b/src/util/lp/hnf_cutter.h index 90cdd5a6d..dff0b8ef8 100644 --- a/src/util/lp/hnf_cutter.h +++ b/src/util/lp/hnf_cutter.h @@ -162,8 +162,7 @@ public: vector transform_to_local_columns(const vector & x) const { vector ret; for (unsigned j = 0; j < vars().size(); j++) { - lp_assert(is_zero(x[m_var_register.local_to_external(j)].y)); - ret.push_back(x[m_var_register.local_to_external(j)].x); + ret.push_back(x[m_var_register.local_to_external(j)].x); } return ret; } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 2cf0c214d..99a0c5883 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2233,7 +2233,7 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term unsigned j; bool is_int; if (m_var_register.external_is_used(tj, j, is_int) == false) - return false; // the term does not have bound because it does not correspond to a column + return false; // the term does not have a bound because it does not correspond to a column if (!is_int) // todo - allow for the next version of hnf return false; impq term_val; From 0170a9772a8ad52e86d1aa12f108a8dca652fcf2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jul 2018 16:44:48 -0700 Subject: [PATCH 044/118] expose methods for dumping T-lemmas from theory_lra Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 17c850330..5f6a48306 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1733,6 +1733,7 @@ public: void assign(literal lit) { // SASSERT(validate_assign(lit)); + dump_assign(lit); if (m_core.size() < small_lemma_size() && m_eqs.empty()) { m_core2.reset(); for (auto const& c : m_core) { @@ -2557,6 +2558,7 @@ public: } } // SASSERT(validate_conflict()); + dump_conflict(); ctx().set_conflict( ctx().mk_justification( ext_theory_conflict_justification( @@ -2714,10 +2716,13 @@ public: } }; - bool validate_conflict() { + void dump_conflict() { if (dump_lemmas()) { ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); } + } + + bool validate_conflict() { if (m_arith_params.m_arith_mode != AS_NEW_ARITH) return true; scoped_arith_mode _sa(ctx().get_fparams()); context nctx(m, ctx().get_fparams(), ctx().get_params()); @@ -2729,10 +2734,13 @@ public: return result; } - bool validate_assign(literal lit) { + void dump_assign(literal lit) { if (dump_lemmas()) { ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); } + } + + bool validate_assign(literal lit) { if (m_arith_params.m_arith_mode != AS_NEW_ARITH) return true; scoped_arith_mode _sa(ctx().get_fparams()); context nctx(m, ctx().get_fparams(), ctx().get_params()); @@ -2758,13 +2766,13 @@ public: } void add_background(context& nctx) { - for (unsigned i = 0; i < m_core.size(); ++i) { + for (literal c : m_core) { expr_ref tmp(m); - ctx().literal2expr(m_core[i], tmp); + ctx().literal2expr(c, tmp); nctx.assert_expr(tmp); } - for (unsigned i = 0; i < m_eqs.size(); ++i) { - nctx.assert_expr(m.mk_eq(m_eqs[i].first->get_owner(), m_eqs[i].second->get_owner())); + for (auto const& eq : m_eqs) { + nctx.assert_expr(m.mk_eq(eq.first->get_owner(), eq.second->get_owner())); } } From 5e5f46f0f845f60e5226eadb6768de6fe4f528bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jul 2018 17:34:45 -0700 Subject: [PATCH 045/118] handle cancelation from nra_solver gracefully Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context_pp.cpp | 2 ++ src/util/lp/nra_solver.cpp | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 3a2aacd26..623141038 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -419,6 +419,7 @@ namespace smt { visitor.collect(fmls); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); + out << "(check-sat)\n"; } static unsigned g_lemma_id = 0; @@ -464,6 +465,7 @@ namespace smt { visitor.collect(fmls); visitor.display_decls(out); visitor.display_asserts(out, fmls, true); + out << "(check-sat)\n"; } void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, diff --git a/src/util/lp/nra_solver.cpp b/src/util/lp/nra_solver.cpp index b1ca67274..a4930b357 100644 --- a/src/util/lp/nra_solver.cpp +++ b/src/util/lp/nra_solver.cpp @@ -104,7 +104,18 @@ namespace nra { } // TBD: add variable bounds? - lbool r = m_nlsat->check(); + lbool r = l_undef; + try { + r = m_nlsat->check(); + } + catch (z3_exception&) { + if (m_limit.get_cancel_flag()) { + r = l_undef; + } + else { + throw; + } + } TRACE("arith", display(tout); m_nlsat->display(tout << r << "\n");); switch (r) { case l_true: From e39107c6829c0962a84f377b8762c09fb5615deb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Jul 2018 21:26:51 -0700 Subject: [PATCH 046/118] turn lemma-id into an attribute on the cotext Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 1 + src/smt/smt_context.h | 5 ++-- src/smt/smt_context_pp.cpp | 30 ++++++++--------------- src/smt/theory_lra.cpp | 50 ++++++++++++++++++-------------------- 4 files changed, 37 insertions(+), 49 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index be4e8321f..44147c668 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -51,6 +51,7 @@ namespace smt { m_relevancy_propagator(mk_relevancy_propagator(*this)), m_random(p.m_random_seed), m_flushing(false), + m_lemma_id(0), m_progress_callback(nullptr), m_next_progress_sample(0), m_fingerprints(m, m_region), diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 77b4ca79c..2ac5695b3 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -88,6 +88,7 @@ namespace smt { scoped_ptr m_relevancy_propagator; random_gen m_random; bool m_flushing; // (debug support) true when flushing + mutable unsigned m_lemma_id; progress_callback * m_progress_callback; unsigned m_next_progress_sample; @@ -1318,12 +1319,12 @@ namespace smt { void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; + unsigned display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent = false_literal, symbol const& logic = symbol::null) const; void display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; - void display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, + unsigned display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, unsigned num_antecedent_eqs, enode_pair const * antecedent_eqs, literal consequent = false_literal, symbol const& logic = symbol::null) const; diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 623141038..8a75dc48c 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -422,21 +422,15 @@ namespace smt { out << "(check-sat)\n"; } - static unsigned g_lemma_id = 0; - #define BUFFER_SZ 128 - void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent, symbol const& logic) const { - char buffer[BUFFER_SZ]; -#ifdef _WINDOWS - sprintf_s(buffer, BUFFER_SZ, "lemma_%d.smt2", g_lemma_id); -#else - sprintf(buffer, "lemma_%d.smt2", g_lemma_id); -#endif - std::ofstream out(buffer); + unsigned context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, literal consequent, symbol const& logic) const { + std::stringstream strm; + strm << "lemma_" << (++m_lemma_id) << ".smt2"; + std::ofstream out(strm.str()); display_lemma_as_smt_problem(out, num_antecedents, antecedents, consequent, logic); out.close(); - g_lemma_id++; + return m_lemma_id; } void context::display_lemma_as_smt_problem(std::ostream & out, unsigned num_antecedents, literal const * antecedents, @@ -468,19 +462,15 @@ namespace smt { out << "(check-sat)\n"; } - void context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, + unsigned context::display_lemma_as_smt_problem(unsigned num_antecedents, literal const * antecedents, unsigned num_eq_antecedents, enode_pair const * eq_antecedents, literal consequent, symbol const& logic) const { - char buffer[BUFFER_SZ]; -#ifdef _WINDOWS - sprintf_s(buffer, BUFFER_SZ, "lemma_%d.smt2", g_lemma_id); -#else - sprintf(buffer, "lemma_%d.smt2", g_lemma_id); -#endif - std::ofstream out(buffer); + std::stringstream strm; + strm << "lemma_" << (++m_lemma_id) << ".smt2"; + std::ofstream out(strm.str()); display_lemma_as_smt_problem(out, num_antecedents, antecedents, num_eq_antecedents, eq_antecedents, consequent, logic); out.close(); - g_lemma_id++; + return m_lemma_id; } /** diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 5f6a48306..3bdd2d784 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1381,6 +1381,11 @@ public: } } } + if (!coeffs.empty() && coeffs.begin()->m_value.is_neg()) { + offset.neg(); + lower_bound = !lower_bound; + for (auto& kv : coeffs) kv.m_value.neg(); + } app_ref atom(m); app_ref t = coeffs2app(coeffs, rational::zero(), is_int); @@ -1391,17 +1396,8 @@ public: atom = a.mk_le(t, a.mk_numeral(offset, is_int)); } - -#if 0 - expr_ref atom1(m); - proof_ref atomp(m); - ctx().get_rewriter()(atom, atom1, atomp); - if (!m.is_false(atom1) && !m.is_true(atom1)) { - atom = to_app(atom1); - } -#endif TRACE("arith", tout << t << ": " << atom << "\n"; - m_solver->print_term(term, tout << "bound atom: "); tout << (lower_bound?" <= ":" >= ") << k << "\n";); + m_solver->print_term(term, tout << "bound atom: "); tout << (lower_bound?" >= ":" <= ") << k << "\n";); ctx().internalize(atom, true); ctx().mark_as_relevant(atom.get()); return atom; @@ -1430,7 +1426,7 @@ public: return l_false; } case lp::lia_move::cut: { - TRACE("arith", tout << "cutn";); + TRACE("arith", tout << "cut\n";); ++m_stats.m_gomory_cuts; // m_explanation implies term <= k app_ref b = mk_bound(term, k, !upper); @@ -1529,10 +1525,7 @@ public: } } else { - enode_vector::const_iterator it = r->begin_parents(); - enode_vector::const_iterator end = r->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r->get_const_parents()) { if (is_underspecified(parent->get_owner())) { return true; } @@ -1804,12 +1797,11 @@ public: lp_api::bound* lo_inf = end, *lo_sup = end; lp_api::bound* hi_inf = end, *hi_sup = end; - for (unsigned i = 0; i < bounds.size(); ++i) { - lp_api::bound& other = *bounds[i]; - if (&other == &b) continue; - if (b.get_bv() == other.get_bv()) continue; - lp_api::bound_kind kind2 = other.get_bound_kind(); - rational const& k2 = other.get_value(); + for (lp_api::bound* other : bounds) { + if (other == &b) continue; + if (b.get_bv() == other->get_bv()) continue; + lp_api::bound_kind kind2 = other->get_bound_kind(); + rational const& k2 = other->get_value(); if (k1 == k2 && kind1 == kind2) { // the bounds are equivalent. continue; @@ -1819,20 +1811,20 @@ public: if (kind2 == lp_api::lower_t) { if (k2 < k1) { if (lo_inf == end || k2 > lo_inf->get_value()) { - lo_inf = &other; + lo_inf = other; } } else if (lo_sup == end || k2 < lo_sup->get_value()) { - lo_sup = &other; + lo_sup = other; } } else if (k2 < k1) { if (hi_inf == end || k2 > hi_inf->get_value()) { - hi_inf = &other; + hi_inf = other; } } else if (hi_sup == end || k2 < hi_sup->get_value()) { - hi_sup = &other; + hi_sup = other; } } if (lo_inf != end) mk_bound_axiom(b, *lo_inf); @@ -2718,7 +2710,9 @@ public: void dump_conflict() { if (dump_lemmas()) { - ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); + unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); + (void)id; + //SASSERT(id != 55); } } @@ -2736,7 +2730,9 @@ public: void dump_assign(literal lit) { if (dump_lemmas()) { - ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); + unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); + (void)id; + // SASSERT(id != 71); } } From 9f2bafbf10d44e5395c42666b5fbc95dbafcebc0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Jul 2018 08:52:13 -0700 Subject: [PATCH 047/118] tidy model generator Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_generator.cpp | 71 +++++++++++++++------------------ src/smt/smt_model_generator.h | 10 +++-- src/smt/theory_datatype.cpp | 1 + 3 files changed, 39 insertions(+), 43 deletions(-) diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 5417785d6..190f7f79e 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -28,6 +28,15 @@ Revision History: namespace smt { + void fresh_value_proc::get_dependencies(buffer& result) { + result.push_back(model_value_dependency(m_value)); + } + + std::ostream& operator<<(std::ostream& out, model_value_dependency const& src) { + if (src.is_fresh_value()) return out << "fresh!" << src.get_value()->get_idx(); + else return out << "#" << src.get_enode()->get_owner_id(); + } + model_generator::model_generator(ast_manager & m): m_manager(m), m_context(nullptr), @@ -161,20 +170,20 @@ namespace smt { source2color & colors, obj_hashtable & already_traversed, svector & todo) { + if (src.is_fresh_value()) { - // there is an implicit dependency between a fresh value stub of sort S and the root enodes of sort S that are not associated with fresh values. + // there is an implicit dependency between a fresh value stub of + // sort S and the root enodes of sort S that are not associated with fresh values. + // sort * s = src.get_value()->get_sort(); if (already_traversed.contains(s)) return true; bool visited = true; - unsigned sz = roots.size(); - for (unsigned i = 0; i < sz; i++) { - enode * r = roots[i]; + for (enode * r : roots) { if (m_manager.get_sort(r->get_owner()) != s) continue; SASSERT(r == r->get_root()); - model_value_proc * proc = nullptr; - root2proc.find(r, proc); + model_value_proc * proc = root2proc[r]; SASSERT(proc); if (proc->is_fresh()) continue; // r is associated with a fresh value... @@ -192,17 +201,12 @@ namespace smt { enode * n = src.get_enode(); SASSERT(n == n->get_root()); bool visited = true; - model_value_proc * proc = nullptr; - root2proc.find(n, proc); - SASSERT(proc); + model_value_proc * proc = root2proc[n]; buffer dependencies; proc->get_dependencies(dependencies); for (model_value_dependency const& dep : dependencies) { visit_child(dep, colors, todo, visited); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> "; - if (dep.is_fresh_value()) tout << "fresh!" << dep.get_value()->get_idx(); - else tout << "#" << dep.get_enode()->get_owner_id(); - tout << "\n";); + TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " -> " << dep << " already visited: " << visited << "\n";); } return visited; } @@ -215,9 +219,7 @@ namespace smt { svector & todo, svector & sorted_sources) { TRACE("mg_top_sort", tout << "process source, is_fresh: " << src.is_fresh_value() << " "; - if (src.is_fresh_value()) tout << "fresh!" << src.get_value()->get_idx(); - else tout << "#" << src.get_enode()->get_owner_id(); - tout << ", todo.size(): " << todo.size() << "\n";); + tout << src << ", todo.size(): " << todo.size() << "\n";); int color = get_color(colors, src); SASSERT(color != Grey); if (color == Black) @@ -227,17 +229,16 @@ namespace smt { while (!todo.empty()) { source curr = todo.back(); TRACE("mg_top_sort", tout << "current source, is_fresh: " << curr.is_fresh_value() << " "; - if (curr.is_fresh_value()) tout << "fresh!" << curr.get_value()->get_idx(); - else tout << "#" << curr.get_enode()->get_owner_id(); - tout << ", todo.size(): " << todo.size() << "\n";); + tout << curr << ", todo.size(): " << todo.size() << "\n";); switch (get_color(colors, curr)) { case White: set_color(colors, curr, Grey); visit_children(curr, roots, root2proc, colors, already_traversed, todo); break; case Grey: - SASSERT(visit_children(curr, roots, root2proc, colors, already_traversed, todo)); + // SASSERT(visit_children(curr, roots, root2proc, colors, already_traversed, todo)); set_color(colors, curr, Black); + TRACE("mg_top_sort", tout << "append " << curr << "\n";); sorted_sources.push_back(curr); break; case Black: @@ -266,18 +267,15 @@ namespace smt { // topological sort // traverse all extra fresh values... - unsigned sz = m_extra_fresh_values.size(); - for (unsigned i = 0; i < sz; i++) { - extra_fresh_value * f = m_extra_fresh_values[i]; + for (extra_fresh_value * f : m_extra_fresh_values) { process_source(source(f), roots, root2proc, colors, already_traversed, todo, sorted_sources); } // traverse all enodes that are associated with fresh values... - sz = roots.size(); + unsigned sz = roots.size(); for (unsigned i = 0; i < sz; i++) { enode * r = roots[i]; - model_value_proc * proc = nullptr; - root2proc.find(r, proc); + model_value_proc * proc = root2proc[r]; SASSERT(proc); if (!proc->is_fresh()) continue; @@ -303,43 +301,38 @@ namespace smt { TRACE("sorted_sources", for (source const& curr : sources) { if (curr.is_fresh_value()) { - tout << "fresh!" << curr.get_value()->get_idx() << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; + tout << curr << " " << mk_pp(curr.get_value()->get_sort(), m_manager) << "\n"; } else { enode * n = curr.get_enode(); SASSERT(n->get_root() == n); sort * s = m_manager.get_sort(n->get_owner()); - tout << "#" << n->get_owner_id() << " " << mk_pp(s, m_manager); - model_value_proc * proc = 0; - root2proc.find(n, proc); - SASSERT(proc); - tout << " is_fresh: " << proc->is_fresh() << "\n"; + tout << curr << " " << mk_pp(s, m_manager); + tout << " is_fresh: " << root2proc[n]->is_fresh() << "\n"; } }); for (source const& curr : sources) { if (curr.is_fresh_value()) { sort * s = curr.get_value()->get_sort(); - TRACE("model_fresh_bug", tout << "mk fresh!" << curr.get_value()->get_idx() << " : " << mk_pp(s, m_manager) << "\n";); + TRACE("model_fresh_bug", tout << curr << " : " << mk_pp(s, m_manager) << "\n";); expr * val = m_model->get_fresh_value(s); - TRACE("model_fresh_bug", tout << "mk fresh!" << curr.get_value()->get_idx() << " := #" << (val == 0 ? UINT_MAX : val->get_id()) << "\n";); + TRACE("model_fresh_bug", tout << curr << " := #" << (val == nullptr ? UINT_MAX : val->get_id()) << "\n";); m_asts.push_back(val); curr.get_value()->set_value(val); } else { enode * n = curr.get_enode(); SASSERT(n->get_root() == n); - TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << "\n";); + TRACE("mg_top_sort", tout << curr << "\n";); dependencies.reset(); dependency_values.reset(); - model_value_proc * proc = nullptr; - VERIFY(root2proc.find(n, proc)); + model_value_proc * proc = root2proc[n]; SASSERT(proc); proc->get_dependencies(dependencies); for (model_value_dependency const& d : dependencies) { if (d.is_fresh_value()) { CTRACE("mg_top_sort", !d.get_value()->get_value(), - tout << "#" << n->get_owner_id() << " -> "; - tout << "fresh!" << d.get_value()->get_idx() << "\n";); + tout << "#" << n->get_owner_id() << " -> " << d << "\n";); SASSERT(d.get_value()->get_value()); dependency_values.push_back(d.get_value()->get_value()); } diff --git a/src/smt/smt_model_generator.h b/src/smt/smt_model_generator.h index 7466b8877..1f69eb324 100644 --- a/src/smt/smt_model_generator.h +++ b/src/smt/smt_model_generator.h @@ -100,14 +100,16 @@ namespace smt { extra_fresh_value * m_value; //!< When m_fresh == true, contains the sort of the fresh value }; public: - model_value_dependency():m_fresh(true), m_value(nullptr) {} - model_value_dependency(enode * n):m_fresh(false), m_enode(n->get_root()) {} - model_value_dependency(extra_fresh_value * v):m_fresh(true), m_value(v) {} + model_value_dependency():m_fresh(true), m_value(nullptr) { } + explicit model_value_dependency(enode * n):m_fresh(false), m_enode(n->get_root()) {} + explicit model_value_dependency(extra_fresh_value * v) :m_fresh(true), m_value(v) { SASSERT(v); } bool is_fresh_value() const { return m_fresh; } enode * get_enode() const { SASSERT(!is_fresh_value()); return m_enode; } extra_fresh_value * get_value() const { SASSERT(is_fresh_value()); return m_value; } }; + std::ostream& operator<<(std::ostream& out, model_value_dependency const& d); + typedef model_value_dependency source; struct source_hash_proc { @@ -166,7 +168,7 @@ namespace smt { extra_fresh_value * m_value; public: fresh_value_proc(extra_fresh_value * v):m_value(v) {} - void get_dependencies(buffer & result) override { result.push_back(m_value); } + void get_dependencies(buffer & result) override; app * mk_value(model_generator & m, ptr_vector & values) override { return to_app(values[0]); } bool is_fresh() const override { return true; } }; diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 049555297..c3befced6 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -636,6 +636,7 @@ namespace smt { void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } ~datatype_value_proc() override {} void get_dependencies(buffer & result) override { + for (model_value_dependency& d : m_dependencies) { } result.append(m_dependencies.size(), m_dependencies.c_ptr()); } app * mk_value(model_generator & mg, ptr_vector & values) override { From 3a5aebd1d32c8cd889b582dde4277a3e0fb11d67 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 11 Jul 2018 08:52:57 -0700 Subject: [PATCH 048/118] tidy model generator Signed-off-by: Nikolaj Bjorner --- src/smt/theory_datatype.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index c3befced6..049555297 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -636,7 +636,6 @@ namespace smt { void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } ~datatype_value_proc() override {} void get_dependencies(buffer & result) override { - for (model_value_dependency& d : m_dependencies) { } result.append(m_dependencies.size(), m_dependencies.c_ptr()); } app * mk_value(model_generator & mg, ptr_vector & values) override { From bc17b18ed085ed7e2d83ac8c1c7590987b3ea9d8 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Jul 2018 12:01:12 -0700 Subject: [PATCH 049/118] setting smt.arith.solver=6 by default Signed-off-by: Lev Nachmanson --- src/smt/params/smt_params_helper.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 3f4105c34..c39b74722 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -40,7 +40,7 @@ def_module_params(module_name='smt', ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), - ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), + ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), ('arith.nl.gb', BOOL, True, 'groebner Basis computation, this option is ignored when arith.nl=false'), ('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'), From adf0d745c10d5ea791e7e72199807e978bcb8e23 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 6 Jul 2018 10:53:04 -0700 Subject: [PATCH 050/118] rebase Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 3bdd2d784..76852d34a 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1168,9 +1168,8 @@ public: if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - if(!m_solver->is_term(vi)) - return rational::zero(); - + if (!m_solver->is_term(vi)) + return rational::zero(); m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { From 3c230727bb35100bbc01dea26c6a4eb152b1902d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 6 Jul 2018 11:13:38 -0700 Subject: [PATCH 051/118] rebase Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 76852d34a..3bdd2d784 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1168,8 +1168,9 @@ public: if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - if (!m_solver->is_term(vi)) - return rational::zero(); + if(!m_solver->is_term(vi)) + return rational::zero(); + m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); while (!m_todo_terms.empty()) { From 5cfc3591d21c88529d1d0e7366cb09444f9c8f0d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 7 Jul 2018 16:18:42 -0700 Subject: [PATCH 052/118] create hnf cuts too, when gomory_cut_period is 2 Signed-off-by: Lev Nachmanson --- src/smt/params/smt_params_helper.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index c39b74722..3f4105c34 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -40,7 +40,7 @@ def_module_params(module_name='smt', ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), ('bv.enable_int2bv', BOOL, True, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), - ('arith.solver', UINT, 6, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), + ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination 4 - utvpi, 5 - infinitary lra, 6 - lra solver'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), ('arith.nl.gb', BOOL, True, 'groebner Basis computation, this option is ignored when arith.nl=false'), ('arith.nl.branching', BOOL, True, 'branching on integer variables in non linear clusters'), From 2dfb8f53b62b2f72cfed0a536dbeabaa599d9e77 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 10 Jul 2018 14:25:22 -0700 Subject: [PATCH 053/118] do not add term to hnf if one of the vars has v.y value Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 32 ++++++++++++++++++++++---------- src/util/lp/lar_solver.h | 1 + 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 99a0c5883..135700936 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2227,6 +2227,17 @@ void lar_solver::round_to_integer_solution() { update_delta_for_terms(del, j, vars_to_terms[j]); } } +// return true if all y coords are zeroes +bool lar_solver::sum_first_coords(const lar_term& t, mpq & val) const { + val = zero_of_type(); + for (const auto & c : t) { + const auto & x = m_mpq_lar_core_solver.m_r_x[c.var()]; + if (!is_zero(x.y)) + return false; + val += x.x * c.coeff(); + } + return true; +} bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci) const { unsigned tj = term_index + m_terms_start_index; @@ -2236,26 +2247,27 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term return false; // the term does not have a bound because it does not correspond to a column if (!is_int) // todo - allow for the next version of hnf return false; - impq term_val; - bool term_val_ready = false; + bool rs_is_calculated = false; mpq b; bool is_strict; + const lar_term& t = *terms()[term_index]; if (has_upper_bound(j, ci, b, is_strict) && !is_strict) { lp_assert(b.is_int()); - term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x); - term_val_ready = true; - if (term_val.x == b) { - rs = b; + if (!sum_first_coords(t, rs)) + return false; + rs_is_calculated = true; + if (rs == b) { return true; } } if (has_lower_bound(j, ci, b, is_strict) && !is_strict) { - if (!term_val_ready) - term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x); + if (!rs_is_calculated){ + if (!sum_first_coords(t, rs)) + return false; + } lp_assert(b.is_int()); - if (term_val.x == b) { - rs = b; + if (rs == b) { return true; } } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index f17aa4a0d..9e15fc472 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -577,5 +577,6 @@ public: bool remove_from_basis(unsigned); lar_term get_term_to_maximize(unsigned ext_j) const; void set_cut_strategy(unsigned cut_frequency); + bool sum_first_coords(const lar_term& t, mpq & val) const; }; } From e0e893b791ce661e68d0a9943b2ac1614637a79f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 11 Jul 2018 12:29:09 -0700 Subject: [PATCH 054/118] fix in hnf for the lower bounds Signed-off-by: Lev Nachmanson --- src/util/lp/general_matrix.h | 4 ++-- src/util/lp/hnf_cutter.h | 15 ++++++++++++--- src/util/lp/int_solver.cpp | 5 +++-- src/util/lp/lar_solver.cpp | 4 +++- src/util/lp/lar_solver.h | 2 +- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/util/lp/general_matrix.h b/src/util/lp/general_matrix.h index ce510eb6e..1c643161a 100644 --- a/src/util/lp/general_matrix.h +++ b/src/util/lp/general_matrix.h @@ -105,12 +105,12 @@ public: } template - void init_row_from_container(int i, const T & c, std::function column_fix) { + void init_row_from_container(int i, const T & c, std::function column_fix, const mpq& sign) { auto & row = m_data[adjust_row(i)]; lp_assert(row_is_initialized_correctly(row)); for (const auto & p : c) { unsigned j = adjust_column(column_fix(p.var())); - row[j] = p.coeff(); + row[j] = sign * p.coeff(); } } diff --git a/src/util/lp/hnf_cutter.h b/src/util/lp/hnf_cutter.h index dff0b8ef8..061b3a130 100644 --- a/src/util/lp/hnf_cutter.h +++ b/src/util/lp/hnf_cutter.h @@ -29,6 +29,7 @@ class hnf_cutter { var_register m_var_register; general_matrix m_A; vector m_terms; + vector m_terms_upper; svector m_constraints_for_explanation; vector m_right_sides; lp_settings & m_settings; @@ -54,15 +55,22 @@ public: // m_A will be filled from scratch in init_matrix_A m_var_register.clear(); m_terms.clear(); + m_terms_upper.clear(); m_constraints_for_explanation.clear(); m_right_sides.clear(); m_abs_max = zero_of_type(); m_overflow = false; } - void add_term(const lar_term* t, const mpq &rs, constraint_index ci) { + void add_term(const lar_term* t, const mpq &rs, constraint_index ci, bool upper_bound) { m_terms.push_back(t); - m_right_sides.push_back(rs); + m_terms_upper.push_back(upper_bound); + if (upper_bound) + m_right_sides.push_back(rs); + else + m_right_sides.push_back(-rs); + m_constraints_for_explanation.push_back(ci); + for (const auto &p : *t) { m_var_register.add_var(p.var()); mpq t = abs(ceil(p.coeff())); @@ -76,7 +84,8 @@ public: } void initialize_row(unsigned i) { - m_A.init_row_from_container(i, * m_terms[i], [this](unsigned j) { return m_var_register.add_var(j);}); + mpq sign = m_terms_upper[i]? one_of_type(): - one_of_type(); + m_A.init_row_from_container(i, * m_terms[i], [this](unsigned j) { return m_var_register.add_var(j);}, sign); } void init_matrix_A() { diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index f49ecabfd..e58abb4fd 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -537,8 +537,9 @@ void int_solver::try_add_term_to_A_for_hnf(unsigned i) { mpq rs; const lar_term* t = m_lar_solver->terms()[i]; constraint_index ci; - if (!hnf_cutter_is_full() && m_lar_solver->get_equality_and_right_side_for_term_on_current_x(i, rs, ci)) { - m_hnf_cutter.add_term(t, rs, ci); + bool upper_bound; + if (!hnf_cutter_is_full() && m_lar_solver->get_equality_and_right_side_for_term_on_current_x(i, rs, ci, upper_bound)) { + m_hnf_cutter.add_term(t, rs, ci, upper_bound); } } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 135700936..f8d16ab8c 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2239,7 +2239,7 @@ bool lar_solver::sum_first_coords(const lar_term& t, mpq & val) const { return true; } -bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci) const { +bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci, bool &upper_bound) const { unsigned tj = term_index + m_terms_start_index; unsigned j; bool is_int; @@ -2257,6 +2257,7 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term return false; rs_is_calculated = true; if (rs == b) { + upper_bound = true; return true; } } @@ -2268,6 +2269,7 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term lp_assert(b.is_int()); if (rs == b) { + upper_bound = false; return true; } } diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 9e15fc472..72705dfb3 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -573,7 +573,7 @@ public: unsigned column_count() const { return A_r().column_count(); } const vector & r_basis() const { return m_mpq_lar_core_solver.r_basis(); } const vector & r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); } - bool get_equality_and_right_side_for_term_on_current_x(unsigned i, mpq &rs, constraint_index& ci) const; + bool get_equality_and_right_side_for_term_on_current_x(unsigned i, mpq &rs, constraint_index& ci, bool &upper_bound) const; bool remove_from_basis(unsigned); lar_term get_term_to_maximize(unsigned ext_j) const; void set_cut_strategy(unsigned cut_frequency); From b7ea90c12be97e33a06192a58398c8e0097085b4 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 12 Jul 2018 18:36:09 +0100 Subject: [PATCH 055/118] bv_decl_plugin: remove some mem allocs of parameters --- src/ast/bv_decl_plugin.cpp | 6 +++--- src/util/trace.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 4869949b7..6bbe3ce13 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -401,7 +401,7 @@ bool bv_decl_plugin::get_int2bv_size(unsigned num_parameters, parameter const * m_manager->raise_exception("int2bv expects one parameter"); return false; } - parameter p(parameters[0]); + const parameter &p = parameters[0]; if (p.is_int()) { result = p.get_int(); return true; @@ -428,7 +428,7 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const // After SMT-COMP, I should find all offending modules. // For now, I will just simplify the numeral here. parameter p0(mod(parameters[0].get_rational(), rational::power_of_two(bv_size))); - parameter ps[2] = { p0, parameters[1] }; + parameter ps[2] = { std::move(p0), parameters[1] }; sort * bv = get_bv_sort(bv_size); return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps)); } @@ -746,7 +746,7 @@ void bv_decl_plugin::get_op_names(svector & op_names, symbol const expr * bv_decl_plugin::get_some_value(sort * s) { SASSERT(s->is_sort_of(m_family_id, BV_SORT)); unsigned bv_size = s->get_parameter(0).get_int(); - parameter p[2] = { parameter(rational(0)), parameter(static_cast(bv_size)) }; + parameter p[2] = { parameter(rational::zero()), parameter(static_cast(bv_size)) }; return m_manager->mk_app(m_family_id, OP_BV_NUM, 2, p, 0, nullptr); } diff --git a/src/util/trace.h b/src/util/trace.h index c0dc90f23..1a245036f 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -51,7 +51,6 @@ void finalize_trace(); static inline void enable_trace(const char * tag) {} static inline void enable_all_trace(bool flag) {} static inline void disable_trace(const char * tag) {} -// On a default Visual C++ build on Windows, a non-void function either needs to return a value, or we have to add: #pragma warning(default:4716) static inline bool is_trace_enabled(const char * tag) { return false; } static inline void close_trace() {} static inline void open_trace() {} From 4915fb080b8978118499bbb6c47a16ef104a0272 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Jul 2018 22:45:52 -0700 Subject: [PATCH 056/118] fix #1749 by rejecting non-well-founded use of datatype in array Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 11 +++++------ src/ast/ast.h | 24 +++++++++++++++++++----- src/ast/datatype_decl_plugin.cpp | 28 +++++++++++++++------------- src/ast/seq_decl_plugin.cpp | 3 +-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f164d6a4f..9ce1b582d 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1934,8 +1934,7 @@ sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * c vector ps; bool change = false; sort_ref_vector sorts(*this); - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (parameter const& p : s->parameters()) { if (p.is_ast()) { SASSERT(is_sort(p.get_ast())); change = true; @@ -2330,8 +2329,8 @@ bool ast_manager::is_label_lit(expr const * n, buffer & names) const { return false; } func_decl const * decl = to_app(n)->get_decl(); - for (unsigned i = 0; i < decl->get_num_parameters(); i++) - names.push_back(decl->get_parameter(i).get_symbol()); + for (parameter const& p : decl->parameters()) { + names.push_back(p.get_symbol()); return true; } @@ -2928,8 +2927,8 @@ bool ast_manager::is_quant_inst(expr const* e, expr*& not_q_or_i, ptr_vectorget_arg(0); func_decl* d = to_app(e)->get_decl(); SASSERT(binding.empty()); - for (unsigned i = 0; i < d->get_num_parameters(); ++i) { - binding.push_back(to_expr(d->get_parameter(i).get_ast())); + for (parameter const& p : d->parameters()) { + binding.push_back(to_expr(p.get_ast())); } return true; } diff --git a/src/ast/ast.h b/src/ast/ast.h index 7cd1dff93..364be8a77 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -273,6 +273,14 @@ public: parameter const * get_parameters() const { return m_parameters.begin(); } bool private_parameters() const { return m_private_parameters; } + struct iterator { + decl_info const& d; + iterator(decl_info const& d) : d(d) {} + parameter const* begin() const { return d.get_parameters(); } + parameter const* end() const { return begin() + d.get_num_parameters(); } + }; + iterator parameters() const { return iterator(*this); } + unsigned hash() const; bool operator==(decl_info const & info) const; }; @@ -571,6 +579,16 @@ public: parameter const & get_parameter(unsigned idx) const { return m_info->get_parameter(idx); } parameter const * get_parameters() const { return m_info == nullptr ? nullptr : m_info->get_parameters(); } bool private_parameters() const { return m_info != nullptr && m_info->private_parameters(); } + + struct iterator { + decl const& d; + iterator(decl const& d) : d(d) {} + parameter const* begin() const { return d.get_parameters(); } + parameter const* end() const { return begin() + d.get_num_parameters(); } + }; + iterator parameters() const { return iterator(*this); } + + }; // ----------------------------------- @@ -2401,11 +2419,7 @@ public: } void reset() { - ptr_buffer::iterator it = m_to_unmark.begin(); - ptr_buffer::iterator end = m_to_unmark.end(); - for (; it != end; ++it) { - reset_mark(*it); - } + for (ast* a : m_to_unmark) reset_mark(a); m_to_unmark.reset(); } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index d3704a84a..284c4df93 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -692,6 +692,7 @@ namespace datatype { } unsigned num_well_founded = 0, id = 0; bool changed; + ptr_vector subsorts; do { changed = false; for (unsigned tid = 0; tid < num_types; tid++) { @@ -701,23 +702,25 @@ namespace datatype { sort* s = sorts[tid]; def const& d = get_def(s); for (constructor const* c : d) { - bool found_nonwf = false; for (accessor const* a : *c) { - if (sort2id.find(a->range(), id) && !well_founded[id]) { - found_nonwf = true; - break; + subsorts.reset(); + get_subsorts(a->range(), subsorts); + for (sort* srt : subsorts) { + if (sort2id.find(srt, id) && !well_founded[id]) { + goto next_constructor; + } } } - if (!found_nonwf) { - changed = true; - well_founded[tid] = true; - num_well_founded++; - break; - } + changed = true; + well_founded[tid] = true; + num_well_founded++; + break; + next_constructor: + ; } } } - while(changed && num_well_founded < num_types); + while (changed && num_well_founded < num_types); return num_well_founded == num_types; } @@ -727,8 +730,7 @@ namespace datatype { void util::get_subsorts(sort* s, ptr_vector& sorts) const { sorts.push_back(s); - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (parameter const& p : s->parameters()) { if (p.is_ast() && is_sort(p.get_ast())) { get_subsorts(to_sort(p.get_ast()), sorts); } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index cd8571a95..00ba93ccb 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -376,8 +376,7 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { if (s->get_family_id() == sP->get_family_id() && s->get_decl_kind() == sP->get_decl_kind() && s->get_num_parameters() == sP->get_num_parameters()) { - for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter const& p = s->get_parameter(i); + for (parameter const& p : s->parameters()) { if (p.is_ast() && is_sort(p.get_ast())) { parameter const& p2 = sP->get_parameter(i); if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false; From ca12a8482f0dd2affa51967a49e0248aaa9e5388 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Jul 2018 22:50:24 -0700 Subject: [PATCH 057/118] fix to closure Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 9ce1b582d..a927df3b5 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2329,7 +2329,7 @@ bool ast_manager::is_label_lit(expr const * n, buffer & names) const { return false; } func_decl const * decl = to_app(n)->get_decl(); - for (parameter const& p : decl->parameters()) { + for (parameter const& p : decl->parameters()) names.push_back(p.get_symbol()); return true; } From 167969d6c2148b274749eaa98967862912e59d61 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jul 2018 07:52:36 -0700 Subject: [PATCH 058/118] remove debug/non-debug difference Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 2 -- src/util/lp/hnf_cutter.h | 28 +++++++++++++--------------- src/util/lp/int_solver.cpp | 26 ++++++++++++++++++-------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 3bdd2d784..ff5b72159 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2712,7 +2712,6 @@ public: if (dump_lemmas()) { unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); (void)id; - //SASSERT(id != 55); } } @@ -2732,7 +2731,6 @@ public: if (dump_lemmas()) { unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); (void)id; - // SASSERT(id != 71); } } diff --git a/src/util/lp/hnf_cutter.h b/src/util/lp/hnf_cutter.h index dff0b8ef8..9a06e1bc9 100644 --- a/src/util/lp/hnf_cutter.h +++ b/src/util/lp/hnf_cutter.h @@ -177,43 +177,41 @@ public: bool overflow() const { return m_overflow; } - lia_move create_cut(lar_term& t, mpq& k, explanation& ex, bool & upper - #ifdef Z3DEBUG - , - const vector & x0 - #endif - ) { + lia_move create_cut(lar_term& t, mpq& k, explanation& ex, bool & upper, const vector & x0) { // we suppose that x0 has at least one non integer element + (void)x0; + init_matrix_A(); svector basis_rows; mpq big_number = m_abs_max.expt(3); mpq d = hnf_calc::determinant_of_rectangular_matrix(m_A, basis_rows, big_number); - // std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl; - //std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl; + // std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl; + // std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl; if (d >= big_number) { return lia_move::undef; } - if (m_settings.get_cancel_flag()) + if (m_settings.get_cancel_flag()) { return lia_move::undef; + } + if (basis_rows.size() < m_A.row_count()) { m_A.shrink_to_rank(basis_rows); shrink_explanation(basis_rows); } - hnf h(m_A, d); - // general_matrix A_orig = m_A; - + hnf h(m_A, d); vector b = create_b(basis_rows); lp_assert(m_A * x0 == b); - // vector bcopy = b; find_h_minus_1_b(h.W(), b); - // lp_assert(bcopy == h.W().take_first_n_columns(b.size()) * b); int cut_row = find_cut_row_index(b); - if (cut_row == -1) + + if (cut_row == -1) { return lia_move::undef; + } + // the matrix is not square - we can get // all integers in b's projection diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index f49ecabfd..8bc2056b4 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -577,17 +577,27 @@ lia_move int_solver::make_hnf_cut() { return lia_move::undef; } settings().st().m_hnf_cutter_calls++; - TRACE("hnf_cut", tout << "settings().st().m_hnf_cutter_calls = " << settings().st().m_hnf_cutter_calls;); + TRACE("hnf_cut", tout << "settings().st().m_hnf_cutter_calls = " << settings().st().m_hnf_cutter_calls << "\n"; + for (unsigned i : m_hnf_cutter.constraints_for_explanation()) { + m_lar_solver->print_constraint(i, tout); + } + m_lar_solver->print_constraints(tout); + ); #ifdef Z3DEBUG vector x0 = m_hnf_cutter.transform_to_local_columns(m_lar_solver->m_mpq_lar_core_solver.m_r_x); +#else + vector x0; #endif - lia_move r = m_hnf_cutter.create_cut(*m_t, *m_k, *m_ex, *m_upper -#ifdef Z3DEBUG - , x0 -#endif - ); - CTRACE("hnf_cut", r == lia_move::cut, tout<< "cut:"; m_lar_solver->print_term(*m_t, tout); tout << " <= " << *m_k << std::endl;); - if (r == lia_move::cut) { + lia_move r = m_hnf_cutter.create_cut(*m_t, *m_k, *m_ex, *m_upper, x0); + + if (r == lia_move::cut) { + TRACE("hnf_cut", + m_lar_solver->print_term(*m_t, tout << "cut:"); + tout << " <= " << *m_k << std::endl; + for (unsigned i : m_hnf_cutter.constraints_for_explanation()) { + m_lar_solver->print_constraint(i, tout); + } + ); lp_assert(current_solution_is_inf_on_cut()); settings().st().m_hnf_cuts++; m_ex->clear(); From 774fa33bfe050bc8f035290b794d7f838114bc2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jul 2018 08:49:46 -0700 Subject: [PATCH 059/118] fix parameter lookup Signed-off-by: Nikolaj Bjorner --- src/ast/seq_decl_plugin.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 00ba93ccb..07c6fd06a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -363,12 +363,12 @@ bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) { bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { if (s == sP) return true; - unsigned i; - if (is_sort_param(sP, i)) { - if (binding.size() <= i) binding.resize(i+1); - if (binding[i] && (binding[i] != s)) return false; - TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, *m_manager) << "\n";); - binding[i] = s; + unsigned idx; + if (is_sort_param(sP, idx)) { + if (binding.size() <= idx) binding.resize(idx+1); + if (binding[idx] && (binding[idx] != s)) return false; + TRACE("seq_verbose", tout << "setting binding @ " << idx << " to " << mk_pp(s, *m_manager) << "\n";); + binding[idx] = s; return true; } @@ -376,7 +376,8 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { if (s->get_family_id() == sP->get_family_id() && s->get_decl_kind() == sP->get_decl_kind() && s->get_num_parameters() == sP->get_num_parameters()) { - for (parameter const& p : s->parameters()) { + for (unsigned i = 0, sz = s->get_num_parameters(); i < sz; ++i) { + parameter const& p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { parameter const& p2 = sP->get_parameter(i); if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false; From 88f4ce68fd46b2200c9d75d568eded5accc4c27f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jul 2018 13:51:07 -0700 Subject: [PATCH 060/118] fix model generation regression exposed in nightly builds Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ff5b72159..9c054830c 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1118,7 +1118,7 @@ public: (v != null_theory_var) && (v < static_cast(m_theory_var2var_index.size())) && (UINT_MAX != m_theory_var2var_index[v]) && - !m_variable_values.empty(); + (!m_variable_values.empty() || m_solver->is_term(m_theory_var2var_index[v])); } bool can_get_bound(theory_var v) const { @@ -1163,13 +1163,19 @@ public: } rational get_value(theory_var v) const { - if (!can_get_value(v)) return rational::zero(); + + if (v == null_theory_var || + v >= static_cast(m_theory_var2var_index.size())) + return rational::zero(); + lp::var_index vi = m_theory_var2var_index[v]; if (m_variable_values.count(vi) > 0) return m_variable_values[vi]; - if(!m_solver->is_term(vi)) + if (!m_solver->is_term(vi)) { + TRACE("arith", tout << "not a term v" << v << "\n";); return rational::zero(); + } m_todo_terms.push_back(std::make_pair(vi, rational::one())); rational result(0); From bdd8685146c91a159c5cb336d8dc439787eb49b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Jul 2018 18:09:30 -0700 Subject: [PATCH 061/118] use params for arguments to Fixedpoint methods Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Fixedpoint.cs | 4 ++-- src/smt/theory_lra.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/api/dotnet/Fixedpoint.cs b/src/api/dotnet/Fixedpoint.cs index e2fb7fe5a..102a96ac5 100644 --- a/src/api/dotnet/Fixedpoint.cs +++ b/src/api/dotnet/Fixedpoint.cs @@ -146,7 +146,7 @@ namespace Microsoft.Z3 /// The query is satisfiable if there is an instance of some relation that is non-empty. /// The query is unsatisfiable if there are no derivations satisfying any of the relations. /// - public Status Query(FuncDecl[] relations) + public Status Query(params FuncDecl[] relations) { Contract.Requires(relations != null); Contract.Requires(Contract.ForAll(0, relations.Length, i => relations[i] != null)); @@ -262,7 +262,7 @@ namespace Microsoft.Z3 /// /// Convert benchmark given as set of axioms, rules and queries to a string. /// - public string ToString(BoolExpr[] queries) + public string ToString(params BoolExpr[] queries) { return Native.Z3_fixedpoint_to_string(Context.nCtx, NativeObject, diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 9c054830c..ef1cd5f0a 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1163,10 +1163,12 @@ public: } rational get_value(theory_var v) const { - + if (v == null_theory_var || - v >= static_cast(m_theory_var2var_index.size())) + v >= static_cast(m_theory_var2var_index.size())) { + TRACE("arith", tout << "Variable v" << v << " not internalized\n";); return rational::zero(); + } lp::var_index vi = m_theory_var2var_index[v]; if (m_variable_values.count(vi) > 0) @@ -1207,6 +1209,7 @@ public: if (!m.canceled() && m_solver.get() && th.get_num_vars() > 0) { reset_variable_values(); m_solver->get_model(m_variable_values); + TRACE("arith", display(tout);); } } @@ -2642,6 +2645,7 @@ public: } else { rational r = get_value(v); + TRACE("arith", tout << "v" << v << " := " << r << "\n";); if (a.is_int(o) && !r.is_int()) r = floor(r); return alloc(expr_wrapper_proc, m_factory->mk_value(r, m.get_sort(o))); } From 7d20fbb28094f27e399d4d8cbc47bcee93f572f0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 14 Jul 2018 12:21:43 +0100 Subject: [PATCH 062/118] do not cooperate if OMP mode is disabled (i.e. it's single threaded only) --- src/util/cooperate.cpp | 31 ++++--------------------------- src/util/cooperate.h | 19 ++++--------------- src/util/mpq.h | 3 --- 3 files changed, 8 insertions(+), 45 deletions(-) diff --git a/src/util/cooperate.cpp b/src/util/cooperate.cpp index 2b2e7958e..df8f67968 100644 --- a/src/util/cooperate.cpp +++ b/src/util/cooperate.cpp @@ -16,6 +16,8 @@ Author: Notes: --*/ + +#ifndef _NO_OMP_ #include "util/cooperate.h" #include "util/trace.h" #include "util/debug.h" @@ -36,7 +38,7 @@ struct cooperation_lock { } }; -cooperation_lock g_lock; +static cooperation_lock g_lock; bool cooperation_ctx::g_cooperate = false; @@ -59,29 +61,4 @@ void cooperation_ctx::checkpoint(char const * task) { } } -cooperation_section::cooperation_section() { - SASSERT(!cooperation_ctx::enabled()); - SASSERT(!omp_in_parallel()); - cooperation_ctx::g_cooperate = true; -} - -cooperation_section::~cooperation_section() { - SASSERT(cooperation_ctx::enabled()); - cooperation_ctx::g_cooperate = false; -} - -init_task::init_task(char const * task) { - SASSERT(cooperation_ctx::enabled()); - SASSERT(omp_in_parallel()); - cooperation_ctx::checkpoint(task); -} - -init_task::~init_task() { - int tid = omp_get_thread_num(); - if (g_lock.m_owner_thread == tid) { - g_lock.m_owner_thread = -1; - omp_unset_nest_lock(&(g_lock.m_lock)); - } -} - - +#endif diff --git a/src/util/cooperate.h b/src/util/cooperate.h index af2cff55c..6220c4c51 100644 --- a/src/util/cooperate.h +++ b/src/util/cooperate.h @@ -19,10 +19,9 @@ Notes: #ifndef COOPERATE_H_ #define COOPERATE_H_ -class cooperation_section; +#ifndef _NO_OMP_ class cooperation_ctx { - friend class cooperation_section; static bool g_cooperate; public: static bool enabled() { return g_cooperate; } @@ -33,18 +32,8 @@ inline void cooperate(char const * task) { if (cooperation_ctx::enabled()) cooperation_ctx::checkpoint(task); } -// must be declared before "#pragma parallel" to enable cooperation -class cooperation_section { -public: - cooperation_section(); - ~cooperation_section(); -}; - -// must be first declaration inside "#pragma parallel for" -class init_task { -public: - init_task(char const * task); - ~init_task(); -}; +#else +inline void cooperate(char const *) {} +#endif #endif diff --git a/src/util/mpq.h b/src/util/mpq.h index b7bdbf400..77301371d 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -814,9 +814,6 @@ public: bool is_even(mpz const & a) { return mpz_manager::is_even(a); } public: bool is_even(mpq const & a) { return is_int(a) && is_even(a.m_num); } - - friend bool operator==(mpq const & a, mpq const & b) ; - friend bool operator>=(mpq const & a, mpq const & b); }; typedef mpq_manager synch_mpq_manager; From b88596283ff4484a835601b49bee8599943fb179 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 14 Jul 2018 20:44:35 +0100 Subject: [PATCH 063/118] don't use mp[zq] synchronized mode if OpenMP mode is disabled --- src/util/mpff.cpp | 10 ++++++++++ src/util/mpff.h | 19 ++++++++++++++++--- src/util/mpfx.cpp | 8 ++++++++ src/util/mpfx.h | 15 +++++++++++++-- src/util/mpq.cpp | 30 ++++++++++++++---------------- src/util/mpq.h | 44 ++++++++++++++++++++++++-------------------- src/util/mpq_inf.cpp | 2 ++ src/util/mpq_inf.h | 4 ++++ src/util/mpz.cpp | 2 ++ src/util/mpz.h | 4 ++++ 10 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index e00a25b1b..8ca2e983f 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -376,9 +376,11 @@ void mpff_manager::set(mpff & n, unsynch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpff_manager::set(mpff & n, synch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#endif template void mpff_manager::set_core(mpff & n, mpq_manager & m, mpq const & v) { @@ -397,9 +399,11 @@ void mpff_manager::set(mpff & n, unsynch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpff_manager::set(mpff & n, synch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#endif bool mpff_manager::eq(mpff const & a, mpff const & b) const { if (is_zero(a) && is_zero(b)) @@ -1077,9 +1081,11 @@ void mpff_manager::significand(mpff const & n, unsynch_mpz_manager & m, mpz & t) significand_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::significand(mpff const & n, synch_mpz_manager & m, mpz & t) { significand_core(n, m, t); } +#endif template void mpff_manager::to_mpz_core(mpff const & n, mpz_manager & m, mpz & t) { @@ -1109,9 +1115,11 @@ void mpff_manager::to_mpz(mpff const & n, unsynch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::to_mpz(mpff const & n, synch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#endif template void mpff_manager::to_mpq_core(mpff const & n, mpq_manager & m, mpq & t) { @@ -1154,9 +1162,11 @@ void mpff_manager::to_mpq(mpff const & n, unsynch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#ifndef _NO_OMP_ void mpff_manager::to_mpq(mpff const & n, synch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#endif void mpff_manager::display_raw(std::ostream & out, mpff const & n) const { if (is_neg(n)) diff --git a/src/util/mpff.h b/src/util/mpff.h index 8023053d2..6f1e9d23c 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -58,9 +58,14 @@ class mpz; class mpq; template class mpz_manager; template class mpq_manager; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; -typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager synch_mpq_manager; +#else +typedef mpz_manager synch_mpz_manager; +typedef mpq_manager synch_mpq_manager; +#endif +typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager unsynch_mpq_manager; class mpff_manager { @@ -213,7 +218,9 @@ public: \brief Return the significand as a mpz numeral. */ void significand(mpff const & n, unsynch_mpz_manager & m, mpz & r); +#ifndef _NO_OMP_ void significand(mpff const & n, synch_mpz_manager & m, mpz & r); +#endif /** \brief Return true if n is negative @@ -378,9 +385,11 @@ public: void set(mpff & n, int64_t num, uint64_t den); void set(mpff & n, mpff const & v); void set(mpff & n, unsynch_mpz_manager & m, mpz const & v); - void set(mpff & n, synch_mpz_manager & m, mpz const & v); void set(mpff & n, unsynch_mpq_manager & m, mpq const & v); +#ifndef _NO_OMP_ void set(mpff & n, synch_mpq_manager & m, mpq const & v); + void set(mpff & n, synch_mpz_manager & m, mpz const & v); +#endif void set_plus_epsilon(mpff & n); void set_minus_epsilon(mpff & n); void set_max(mpff & n); @@ -420,6 +429,7 @@ public: */ void to_mpz(mpff const & n, unsynch_mpz_manager & m, mpz & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpz numeral. @@ -428,6 +438,7 @@ public: \remark if exponent(n) is too big, we may run out of memory. */ void to_mpz(mpff const & n, synch_mpz_manager & m, mpz & t); +#endif /** \brief Convert n into a mpq numeral. @@ -436,13 +447,15 @@ public: */ void to_mpq(mpff const & n, unsynch_mpq_manager & m, mpq & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpq numeral. \remark if exponent(n) is too big, we may run out of memory. */ void to_mpq(mpff const & n, synch_mpq_manager & m, mpq & t); - +#endif + /** \brief Return n as an int64. diff --git a/src/util/mpfx.cpp b/src/util/mpfx.cpp index 2ebc54840..8ed16ec68 100644 --- a/src/util/mpfx.cpp +++ b/src/util/mpfx.cpp @@ -272,9 +272,11 @@ void mpfx_manager::set(mpfx & n, unsynch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpfx_manager::set(mpfx & n, synch_mpz_manager & m, mpz const & v) { set_core(n, m, v); } +#endif template void mpfx_manager::set_core(mpfx & n, mpq_manager & m, mpq const & v) { @@ -309,9 +311,11 @@ void mpfx_manager::set(mpfx & n, unsynch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#ifndef _NO_OMP_ void mpfx_manager::set(mpfx & n, synch_mpq_manager & m, mpq const & v) { set_core(n, m, v); } +#endif bool mpfx_manager::eq(mpfx const & a, mpfx const & b) const { if (is_zero(a) && is_zero(b)) @@ -714,9 +718,11 @@ void mpfx_manager::to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#ifndef _NO_OMP_ void mpfx_manager::to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t) { to_mpz_core(n, m, t); } +#endif template void mpfx_manager::to_mpq_core(mpfx const & n, mpq_manager & m, mpq & t) { @@ -738,9 +744,11 @@ void mpfx_manager::to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#ifndef _NO_OMP_ void mpfx_manager::to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t) { to_mpq_core(n, m, t); } +#endif void mpfx_manager::display_raw(std::ostream & out, mpfx const & n) const { if (is_neg(n)) diff --git a/src/util/mpfx.h b/src/util/mpfx.h index a8e93f0b0..6de3f251b 100644 --- a/src/util/mpfx.h +++ b/src/util/mpfx.h @@ -51,9 +51,14 @@ class mpz; class mpq; template class mpz_manager; template class mpq_manager; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; -typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager synch_mpq_manager; +#else +typedef mpz_manager synch_mpz_manager; +typedef mpq_manager synch_mpq_manager; +#endif +typedef mpz_manager unsynch_mpz_manager; typedef mpq_manager unsynch_mpq_manager; class mpfx_manager { @@ -312,9 +317,11 @@ public: void set(mpfx & n, int64_t num, uint64_t den); void set(mpfx & n, mpfx const & v); void set(mpfx & n, unsynch_mpz_manager & m, mpz const & v); - void set(mpfx & n, synch_mpz_manager & m, mpz const & v); void set(mpfx & n, unsynch_mpq_manager & m, mpq const & v); +#ifndef _NO_OMP_ + void set(mpfx & n, synch_mpz_manager & m, mpz const & v); void set(mpfx & n, synch_mpq_manager & m, mpq const & v); +#endif /** \brief Set n to the smallest representable numeral greater than zero. @@ -359,22 +366,26 @@ public: */ void to_mpz(mpfx const & n, unsynch_mpz_manager & m, mpz & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpz numeral. \pre is_int(n) */ void to_mpz(mpfx const & n, synch_mpz_manager & m, mpz & t); +#endif /** \brief Convert n into a mpq numeral. */ void to_mpq(mpfx const & n, unsynch_mpq_manager & m, mpq & t); +#ifndef _NO_OMP_ /** \brief Convert n into a mpq numeral. */ void to_mpq(mpfx const & n, synch_mpq_manager & m, mpq & t); +#endif /** \brief Return the biggest k s.t. 2^k <= a. diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index 30ac0f410..207614ee0 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -26,12 +26,12 @@ mpq_manager::mpq_manager() { template mpq_manager::~mpq_manager() { - del(m_n_tmp); - del(m_add_tmp1); - del(m_add_tmp2); - del(m_lt_tmp1); - del(m_lt_tmp2); - del(m_addmul_tmp); + del(m_tmp1); + del(m_tmp2); + del(m_tmp3); + del(m_tmp4); + del(m_q_tmp1); + del(m_q_tmp2); } @@ -68,9 +68,9 @@ bool mpq_manager::rat_lt(mpq const & a, mpq const & b) { return r; } else { - mul(na, db, m_lt_tmp1); - mul(nb, da, m_lt_tmp2); - return lt(m_lt_tmp1, m_lt_tmp2); + mul(na, db, m_q_tmp1); + mul(nb, da, m_q_tmp2); + return lt(m_q_tmp1, m_q_tmp2); } } @@ -384,8 +384,7 @@ void mpq_manager::rat_mul(mpq const & a, mpq const & b, mpq & c) { del(tmp2); } else { - mpz& g1 = m_n_tmp, &g2 = m_addmul_tmp.m_num, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2; - rat_mul(a, b, c, g1, g2, tmp1, tmp2); + rat_mul(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } @@ -402,8 +401,7 @@ void mpq_manager::rat_add(mpq const & a, mpq const & b, mpq & c) { del(g); } else { - mpz& g = m_n_tmp, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2, &tmp3 = m_addmul_tmp.m_num; - lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3); + lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } @@ -420,13 +418,13 @@ void mpq_manager::rat_sub(mpq const & a, mpq const & b, mpq & c) { del(g); } else { - mpz& g = m_n_tmp, &tmp1 = m_add_tmp1, &tmp2 = m_add_tmp2, &tmp3 = m_addmul_tmp.m_num; - lin_arith_op(a, b, c, g, tmp1, tmp2, tmp3); + lin_arith_op(a, b, c, m_tmp1, m_tmp2, m_tmp3, m_tmp4); } STRACE("rat_mpq", tout << to_string(c) << "\n";); } +#ifndef _NO_OMP_ template class mpq_manager; +#endif template class mpq_manager; - diff --git a/src/util/mpq.h b/src/util/mpq.h index 77301371d..20802f786 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -41,12 +41,12 @@ inline void swap(mpq & m1, mpq & m2) { m1.swap(m2); } template class mpq_manager : public mpz_manager { - mpz m_n_tmp; - mpz m_add_tmp1; - mpz m_add_tmp2; - mpq m_addmul_tmp; - mpq m_lt_tmp1; - mpq m_lt_tmp2; + mpz m_tmp1; + mpz m_tmp2; + mpz m_tmp3; + mpz m_tmp4; + mpq m_q_tmp1; + mpq m_q_tmp2; void reset_denominator(mpq & a) { del(a.m_den); @@ -66,11 +66,11 @@ class mpq_manager : public mpz_manager { del(tmp); } else { - gcd(a.m_num, a.m_den, m_n_tmp); - if (is_one(m_n_tmp)) + gcd(a.m_num, a.m_den, m_tmp1); + if (is_one(m_tmp1)) return; - div(a.m_num, m_n_tmp, a.m_num); - div(a.m_den, m_n_tmp, a.m_den); + div(a.m_num, m_tmp1, a.m_num); + div(a.m_den, m_tmp1, a.m_den); } } @@ -87,9 +87,9 @@ class mpq_manager : public mpz_manager { del(tmp1); } else { - mul(b, a.m_den, m_add_tmp1); + mul(b, a.m_den, m_tmp1); set(c.m_den, a.m_den); - add(a.m_num, m_add_tmp1, c.m_num); + add(a.m_num, m_tmp1, c.m_num); normalize(c); } STRACE("rat_mpq", tout << to_string(c) << "\n";); @@ -320,8 +320,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - add(a, m_addmul_tmp, d); + mul(b, c, m_q_tmp1); + add(a, m_q_tmp1, d); } } } @@ -342,8 +342,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - add(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + add(a, m_q_tmp1, d); } } } @@ -365,8 +365,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - sub(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + sub(a, m_q_tmp1, d); } } } @@ -387,8 +387,8 @@ public: del(tmp); } else { - mul(b,c,m_addmul_tmp); - sub(a, m_addmul_tmp, d); + mul(b,c, m_q_tmp1); + sub(a, m_q_tmp1, d); } } } @@ -816,7 +816,11 @@ public: bool is_even(mpq const & a) { return is_int(a) && is_even(a.m_num); } }; +#ifndef _NO_OMP_ typedef mpq_manager synch_mpq_manager; +#else +typedef mpq_manager synch_mpq_manager; +#endif typedef mpq_manager unsynch_mpq_manager; typedef _scoped_numeral scoped_mpq; diff --git a/src/util/mpq_inf.cpp b/src/util/mpq_inf.cpp index c6c160941..69de425cf 100644 --- a/src/util/mpq_inf.cpp +++ b/src/util/mpq_inf.cpp @@ -39,5 +39,7 @@ std::string mpq_inf_manager::to_string(mpq_inf const & a) { } +#ifndef _NO_OMP_ template class mpq_inf_manager; +#endif template class mpq_inf_manager; diff --git a/src/util/mpq_inf.h b/src/util/mpq_inf.h index 7b866994d..c7bd261e6 100644 --- a/src/util/mpq_inf.h +++ b/src/util/mpq_inf.h @@ -279,7 +279,11 @@ public: mpq_manager& get_mpq_manager() { return m; } }; +#ifndef _NO_OMP_ typedef mpq_inf_manager synch_mpq_inf_manager; +#else +typedef mpq_inf_manager synch_mpq_inf_manager; +#endif typedef mpq_inf_manager unsynch_mpq_inf_manager; #endif diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 7ad4797b7..32a074eb3 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -2369,5 +2369,7 @@ bool mpz_manager::divides(mpz const & a, mpz const & b) { return r; } +#ifndef _NO_OMP_ template class mpz_manager; +#endif template class mpz_manager; diff --git a/src/util/mpz.h b/src/util/mpz.h index f480b097e..187532a87 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -692,7 +692,11 @@ public: bool decompose(mpz const & n, svector & digits); }; +#ifndef _NO_OMP_ typedef mpz_manager synch_mpz_manager; +#else +typedef mpz_manager synch_mpz_manager; +#endif typedef mpz_manager unsynch_mpz_manager; typedef _scoped_numeral scoped_mpz; From dfa8c4432fed9e1c47b32681c3fcda0389b58ae2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sat, 14 Jul 2018 20:50:49 +0100 Subject: [PATCH 064/118] add parameter(rational&&) --- src/ast/ast.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/ast.h b/src/ast/ast.h index 364be8a77..89df04961 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -122,6 +122,7 @@ public: explicit parameter(ast * p): m_kind(PARAM_AST), m_ast(p) {} explicit parameter(symbol const & s): m_kind(PARAM_SYMBOL), m_symbol(s.c_ptr()) {} explicit parameter(rational const & r): m_kind(PARAM_RATIONAL), m_rational(alloc(rational, r)) {} + explicit parameter(rational && r) : m_kind(PARAM_RATIONAL), m_rational(alloc(rational, std::move(r))) {} explicit parameter(double d):m_kind(PARAM_DOUBLE), m_dval(d) {} explicit parameter(const char *s):m_kind(PARAM_SYMBOL), m_symbol(symbol(s).c_ptr()) {} explicit parameter(unsigned ext_id, bool):m_kind(PARAM_EXTERNAL), m_ext_id(ext_id) {} From f7ac0966965781eda14e468bfba672c9f741490f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 15 Jul 2018 15:29:13 -0700 Subject: [PATCH 065/118] avoid a vector copy Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.h b/src/util/lp/lar_solver.h index 72705dfb3..3735fbb9f 100644 --- a/src/util/lp/lar_solver.h +++ b/src/util/lp/lar_solver.h @@ -112,7 +112,7 @@ private: public : unsigned terms_start_index() const { return m_terms_start_index; } - const vector terms() const { return m_terms; } + const vector & terms() const { return m_terms; } const vector& constraints() const { return m_constraints; } From d00ffdda82e384b8ccb49d9fc952cd2e86ad8bb6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Jul 2018 22:35:47 -0700 Subject: [PATCH 066/118] strengthen filter for specialized tactic conditions, add flag to disable hnf to lp_params Signed-off-by: Nikolaj Bjorner --- src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 44 +++++++++--------- src/smt/smt_setup.cpp | 2 +- src/smt/theory_lra.cpp | 10 ++--- src/tactic/arith/probe_arith.cpp | 60 +++++++++++++++++++++---- src/tactic/fpa/qffplra_tactic.cpp | 21 ++++++++- src/tactic/smtlogics/qfnia_tactic.cpp | 12 ++--- src/util/lp/int_solver.cpp | 3 ++ src/util/lp/lp_params.pyg | 1 + src/util/lp/lp_settings.h | 4 +- 9 files changed, 114 insertions(+), 43 deletions(-) diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 47b9e0505..1b633be70 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -42,26 +42,28 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { else factor = mk_skip_tactic(); - return and_then(and_then(using_params(mk_simplify_tactic(m, p), - main_p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - mk_propagate_values_tactic(m, p), - mk_solve_eqs_tactic(m, p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - mk_elim_uncnstr_tactic(m, p), - mk_elim_term_ite_tactic(m, p)), - and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection - factor, - mk_solve_eqs_tactic(m, p), - using_params(mk_purify_arith_tactic(m, p), - purify_p), - using_params(mk_simplify_tactic(m, p), - main_p), - mk_tseitin_cnf_core_tactic(m, p), - using_params(mk_simplify_tactic(m, p), - main_p), - mk_nlsat_tactic(m, p))); + return and_then( + mk_report_verbose_tactic("(qfnra-nlsat-tactic)", 10), + and_then(using_params(mk_simplify_tactic(m, p), + main_p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + mk_propagate_values_tactic(m, p), + mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + mk_elim_uncnstr_tactic(m, p), + mk_elim_term_ite_tactic(m, p)), + and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection + factor, + mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), + using_params(mk_simplify_tactic(m, p), + main_p), + mk_tseitin_cnf_core_tactic(m, p), + using_params(mk_simplify_tactic(m, p), + main_p), + mk_nlsat_tactic(m, p))); } diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index a85e95b57..932ca597f 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -492,7 +492,7 @@ namespace smt { m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; - m_params.m_nnf_cnf = false; + m_params.m_nnf_cnf = false; setup_lra_arith(); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 3bdd2d784..3b6af0be5 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -298,13 +298,15 @@ class theory_lra::imp { void init_solver() { if (m_solver) return; - lp_params lp(ctx().get_params()); - m_solver = alloc(lp::lar_solver); + + reset_variable_values(); m_theory_var2var_index.reset(); + m_solver = alloc(lp::lar_solver); + lp_params lp(ctx().get_params()); m_solver->settings().set_resource_limit(m_resource_limit); m_solver->settings().simplex_strategy() = static_cast(lp.simplex_strategy()); - reset_variable_values(); m_solver->settings().bound_propagation() = BP_NONE != propagation_mode(); + m_solver->settings().m_enable_hnf = lp.enable_hnf(); m_solver->set_track_pivoted_rows(lp.bprop_on_pivoted_rows()); // todo : do not use m_arith_branch_cut_ratio for deciding on cheap cuts @@ -2712,7 +2714,6 @@ public: if (dump_lemmas()) { unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), false_literal); (void)id; - //SASSERT(id != 55); } } @@ -2732,7 +2733,6 @@ public: if (dump_lemmas()) { unsigned id = ctx().display_lemma_as_smt_problem(m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit); (void)id; - // SASSERT(id != 71); } } diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 36ee89a1b..4c5c17bd5 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -127,6 +127,43 @@ public: } }; +struct has_nlmul { + struct found {}; + ast_manager& m; + arith_util a; + has_nlmul(ast_manager& m):m(m), a(m) {} + + void throw_found(expr* e) { + TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";); + SASSERT(false); + throw found(); + } + + void operator()(var *) { } + + void operator()(quantifier *) { } + + void operator()(app * n) { + family_id fid = n->get_family_id(); + if (fid == a.get_family_id()) { + switch (n->get_decl_kind()) { + case OP_MUL: + if (n->get_num_args() != 2 || !a.is_numeral(n->get_arg(0))) + throw_found(n); + break; + case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: + if (!a.is_numeral(n->get_arg(1))) + throw_found(n); + break; + case OP_POWER: + throw_found(n); + default: + break; + } + } + } +}; + probe * mk_arith_avg_degree_probe() { return alloc(arith_degree_probe, true); } @@ -441,13 +478,13 @@ struct is_non_nira_functor { if (m_linear) { if (n->get_num_args() != 2) throw_found(n); - if (!u.is_numeral(n->get_arg(0))) + if (!u.is_numeral(n->get_arg(0)) && !u.is_numeral(n->get_arg(1))) throw_found(n); } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: if (m_linear && !u.is_numeral(n->get_arg(1))) - throw_found(n); + throw_found(n); return; case OP_IS_INT: if (m_real) @@ -478,27 +515,27 @@ struct is_non_nira_functor { static bool is_qfnia(goal const & g) { is_non_nira_functor p(g.m(), true, false, false, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_qfnra(goal const & g) { is_non_nira_functor p(g.m(), false, true, false, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nia(goal const & g) { is_non_nira_functor p(g.m(), true, false, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nra(goal const & g) { is_non_nira_functor p(g.m(), false, true, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_nira(goal const & g) { is_non_nira_functor p(g.m(), true, true, true, false); - return !test(g, p); + return !test(g, p) && test(g); } static bool is_lra(goal const & g) { @@ -560,12 +597,16 @@ struct is_non_qfufnra_functor { } return; case OP_IDIV: case OP_DIV: case OP_REM: case OP_MOD: - if (!u.is_numeral(n->get_arg(1))) + if (!u.is_numeral(n->get_arg(1))) { + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); + } return; case OP_POWER: - if (!u.is_numeral(n->get_arg(1))) + if (!u.is_numeral(n->get_arg(1))) { + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); + } m_has_nonlinear = true; return; case OP_IS_INT: @@ -574,6 +615,7 @@ struct is_non_qfufnra_functor { throw_found(); return; default: + TRACE("arith", tout << "non-linear " << expr_ref(n, m) << "\n";); throw_found(); } } diff --git a/src/tactic/fpa/qffplra_tactic.cpp b/src/tactic/fpa/qffplra_tactic.cpp index 947a41111..605232772 100644 --- a/src/tactic/fpa/qffplra_tactic.cpp +++ b/src/tactic/fpa/qffplra_tactic.cpp @@ -26,6 +26,23 @@ tactic * mk_qffplra_tactic(ast_manager & m, params_ref const & p) { return st; } +struct is_fpa_function { + struct found {}; + ast_manager & m; + fpa_util fu; + + is_fpa_function(ast_manager & _m) : m(_m), fu(m) {} + + void operator()(var *) { } + + void operator()(quantifier *) { } + + void operator()(app * n) { + if (n->get_family_id() == fu.get_family_id()) + throw found(); + } +}; + struct is_non_qffplra_predicate { struct found {}; ast_manager & m; @@ -61,7 +78,9 @@ struct is_non_qffplra_predicate { class is_qffplra_probe : public probe { public: result operator()(goal const & g) override { - return !test(g); + return + test(g) && + !test(g); } ~is_qffplra_probe() override {} diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 2ef49229a..b92e08006 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -110,9 +110,11 @@ static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { - return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), - try_for(mk_qfnia_smt_solver(m, p), 2000), - mk_qfnia_nlsat_solver(m, p), - mk_qfnia_smt_solver(m, p))); + return and_then( + mk_report_verbose_tactic("(qfnia-tactic)", 10), + mk_qfnia_premable(m, p), + or_else(mk_qfnia_sat_solver(m, p), + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p))); } diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index e58abb4fd..1d0d20c33 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -600,6 +600,9 @@ lia_move int_solver::make_hnf_cut() { } lia_move int_solver::hnf_cut() { + if (!settings().m_enable_hnf) { + return lia_move::undef; + } if ((m_number_of_calls) % settings().hnf_cut_period() == 0) { return make_hnf_cut(); } diff --git a/src/util/lp/lp_params.pyg b/src/util/lp/lp_params.pyg index 7731536f0..1ef788241 100644 --- a/src/util/lp/lp_params.pyg +++ b/src/util/lp/lp_params.pyg @@ -5,6 +5,7 @@ def_module_params('lp', ('min', BOOL, False, 'minimize cost'), ('print_stats', BOOL, False, 'print statistic'), ('simplex_strategy', UINT, 0, 'simplex strategy for the solver'), + ('enable_hnf', BOOL, True, 'enable hnf cuts'), ('bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation') )) diff --git a/src/util/lp/lp_settings.h b/src/util/lp/lp_settings.h index 4e99ecc82..dd19df23a 100644 --- a/src/util/lp/lp_settings.h +++ b/src/util/lp/lp_settings.h @@ -197,6 +197,7 @@ public: bool m_int_patch_only_integer_values; unsigned limit_on_rows_for_hnf_cutter; unsigned limit_on_columns_for_hnf_cutter; + bool m_enable_hnf; unsigned hnf_cut_period() const { return m_hnf_cut_period; } @@ -263,7 +264,8 @@ public: m_int_pivot_fixed_vars_from_basis(false), m_int_patch_only_integer_values(true), limit_on_rows_for_hnf_cutter(75), - limit_on_columns_for_hnf_cutter(150) + limit_on_columns_for_hnf_cutter(150), + m_enable_hnf(true) {} void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; } From 49141c7813eeb8f0e578d4660e7d93fc61adf4b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Jul 2018 08:33:41 +0100 Subject: [PATCH 067/118] remove left-over break assert Signed-off-by: Nikolaj Bjorner --- src/tactic/arith/probe_arith.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/arith/probe_arith.cpp b/src/tactic/arith/probe_arith.cpp index 4c5c17bd5..2e090755b 100644 --- a/src/tactic/arith/probe_arith.cpp +++ b/src/tactic/arith/probe_arith.cpp @@ -135,7 +135,6 @@ struct has_nlmul { void throw_found(expr* e) { TRACE("probe", tout << expr_ref(e, m) << ": " << sort_ref(m.get_sort(e), m) << "\n";); - SASSERT(false); throw found(); } From 8744c62fca91dddc0c88786c8646f716e53e6e45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 16 Jul 2018 10:55:25 +0100 Subject: [PATCH 068/118] fix #1755 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_solver.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index ca0474314..e61a02d80 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -230,11 +230,14 @@ namespace opt { get_model(m_model); inf_eps val2; m_valid_objectives[i] = true; - TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); + TRACE("opt", tout << (has_shared?"has shared":"non-shared") << " " << val << "\n";); if (!m_models[i]) { set_model(i); } - if (m_context.get_context().update_model(has_shared)) { + if (!val.is_finite()) { + // skip model updates + } + else if (m_context.get_context().update_model(has_shared)) { if (has_shared && val != current_objective_value(i)) { decrement_value(i, val); } From 35f7f1f62efaa41d1802f8ce7496a187e9e72849 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 16 Jul 2018 12:29:42 -0700 Subject: [PATCH 069/118] fix in cube heuristic Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index f8d16ab8c..eb5b7d972 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2209,7 +2209,7 @@ void lar_solver::round_to_integer_solution() { fill_vars_to_terms(vars_to_terms); for (unsigned j = 0; j < column_count(); j++) { - if (column_is_int(j)) continue; + if (!column_is_int(j)) continue; if (column_corresponds_to_term(j)) continue; TRACE("cube", m_int_solver->display_column(tout, j);); impq& v = m_mpq_lar_core_solver.m_r_x[j]; From b71fe0b3b7a1a33b59e87c4c46e104fce4883eb3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 16 Jul 2018 16:17:49 -0700 Subject: [PATCH 070/118] speed up find_cube Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index eb5b7d972..041b49389 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -2172,42 +2172,8 @@ bool lar_solver::tighten_term_bounds_by_delta(unsigned term_index, const impq& d return true; } -void lar_solver::update_delta_for_terms(const impq & delta, unsigned j, const vector& terms_of_var) { - for (unsigned i : terms_of_var) { - lar_term & t = *m_terms[i]; - auto it = t.m_coeffs.find(j); - unsigned tj = to_column(i + m_terms_start_index); - TRACE("cube", - tout << "t.apply = " << t.apply(m_mpq_lar_core_solver.m_r_x) << ", m_mpq_lar_core_solver.m_r_x[tj]= " << m_mpq_lar_core_solver.m_r_x[tj];); - TRACE("cube", print_term_as_indices(t, tout); - tout << ", it->second = " << it->second; - tout << ", tj = " << tj << ", "; - m_int_solver->display_column(tout, tj); - ); - - m_mpq_lar_core_solver.m_r_x[tj] += it->second * delta; - lp_assert(t.apply(m_mpq_lar_core_solver.m_r_x) == m_mpq_lar_core_solver.m_r_x[tj]); - TRACE("cube", m_int_solver->display_column(tout, tj); ); - } -} - - -void lar_solver::fill_vars_to_terms(vector> & vars_to_terms) { - for (unsigned j = 0; j < m_terms.size(); j++) { - if (!term_is_used_as_row(j + m_terms_start_index)) - continue; - for (const auto & p : *m_terms[j]) { - if (p.var() >= vars_to_terms.size()) - vars_to_terms.resize(p.var() + 1); - vars_to_terms[p.var()].push_back(j); - } - } -} void lar_solver::round_to_integer_solution() { - vector> vars_to_terms; - fill_vars_to_terms(vars_to_terms); - for (unsigned j = 0; j < column_count(); j++) { if (!column_is_int(j)) continue; if (column_corresponds_to_term(j)) continue; @@ -2223,8 +2189,6 @@ void lar_solver::round_to_integer_solution() { } else { v = flv; } - TRACE("cube", m_int_solver->display_column(tout, j); tout << "v = " << v << " ,del = " << del;); - update_delta_for_terms(del, j, vars_to_terms[j]); } } // return true if all y coords are zeroes From 60bb02b70971e815c1c1e3b1a958b21eeb91af2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Jul 2018 15:31:49 +0100 Subject: [PATCH 071/118] updates Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 17 +++++++++++ src/ast/arith_decl_plugin.h | 1 + src/ast/rewriter/arith_rewriter.cpp | 6 ++++ src/ast/rewriter/arith_rewriter.h | 1 + src/ast/rewriter/seq_rewriter.cpp | 47 +++++++++++++++++++++++++++++ src/ast/rewriter/seq_rewriter.h | 2 ++ src/cmd_context/cmd_context.cpp | 2 +- src/smt/mam.cpp | 23 ++++++++------ src/smt/smt_context.cpp | 37 +++++++++-------------- src/smt/smt_context.h | 3 +- src/smt/theory_seq.cpp | 16 +++++++++- 11 files changed, 120 insertions(+), 35 deletions(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index be3a02019..3c5e2e1c0 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -351,6 +351,7 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) { case OP_MUL: return is_real ? m_r_mul_decl : m_i_mul_decl; case OP_DIV: return m_r_div_decl; case OP_IDIV: return m_i_div_decl; + case OP_IDIVIDES: UNREACHABLE(); case OP_REM: return m_i_rem_decl; case OP_MOD: return m_i_mod_decl; case OP_TO_REAL: return m_to_real_decl; @@ -482,6 +483,14 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters m_manager->raise_exception("no arguments supplied to arithmetical operator"); return nullptr; } + if (k == OP_IDIVIDES) { + if (arity != 1 || domain[0] != m_int_decl || num_parameters != 1 || !parameters[0].is_int()) { + m_manager->raise_exception("invalid divides application. Expects integer parameter and one argument of sort integer"); + } + return m_manager->mk_func_decl(symbol("divides"), 1, &m_int_decl, m_manager->mk_bool_sort(), + func_decl_info(m_family_id, k, num_parameters, parameters)); + } + if (m_manager->int_real_coercions() && use_coercion(k)) { return mk_func_decl(fix_kind(k, arity), has_real_arg(arity, domain, m_real_decl)); } @@ -499,6 +508,13 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters m_manager->raise_exception("no arguments supplied to arithmetical operator"); return nullptr; } + if (k == OP_IDIVIDES) { + if (num_args != 1 || m_manager->get_sort(args[0]) != m_int_decl || num_parameters != 1 || !parameters[0].is_int()) { + m_manager->raise_exception("invalid divides application. Expects integer parameter and one argument of sort integer"); + } + return m_manager->mk_func_decl(symbol("divides"), 1, &m_int_decl, m_manager->mk_bool_sort(), + func_decl_info(m_family_id, k, num_parameters, parameters)); + } if (m_manager->int_real_coercions() && use_coercion(k)) { return mk_func_decl(fix_kind(k, num_args), has_real_arg(m_manager, num_args, args, m_real_decl)); } @@ -533,6 +549,7 @@ void arith_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("*",OP_MUL)); op_names.push_back(builtin_name("/",OP_DIV)); op_names.push_back(builtin_name("div",OP_IDIV)); + op_names.push_back(builtin_name("divides",OP_IDIVIDES)); op_names.push_back(builtin_name("rem",OP_REM)); op_names.push_back(builtin_name("mod",OP_MOD)); op_names.push_back(builtin_name("to_real",OP_TO_REAL)); diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index f5f82b5fd..09f082522 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -46,6 +46,7 @@ enum arith_op_kind { OP_MUL, OP_DIV, OP_IDIV, + OP_IDIVIDES, OP_REM, OP_MOD, OP_TO_REAL, diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 8035254b4..72ce9c761 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -66,6 +66,7 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c SASSERT(num_args == 2); st = mk_div_core(args[0], args[1], result); break; case OP_IDIV: if (num_args == 1) { result = args[0]; st = BR_DONE; break; } SASSERT(num_args == 2); st = mk_idiv_core(args[0], args[1], result); break; + case OP_IDIVIDES: SASSERT(num_args == 1); st = mk_idivides(f->get_parameter(0).get_int(), args[0], result); break; case OP_MOD: SASSERT(num_args == 2); st = mk_mod_core(args[0], args[1], result); break; case OP_REM: SASSERT(num_args == 2); st = mk_rem_core(args[0], args[1], result); break; case OP_UMINUS: SASSERT(num_args == 1); st = mk_uminus(args[0], result); break; @@ -792,6 +793,11 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul return BR_FAILED; } +br_status arith_rewriter::mk_idivides(unsigned k, expr * arg, expr_ref & result) { + result = m().mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0)); + return BR_REWRITE2; +} + br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result) { set_curr_sort(m().get_sort(arg1)); numeral v1, v2; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 93b6e5ad5..dd7623a9b 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -143,6 +143,7 @@ public: br_status mk_div_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_idiv_core(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_idivides(unsigned k, expr * arg, expr_ref & result); br_status mk_mod_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result); br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index af5ef3b0b..a65351a50 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1866,6 +1866,53 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } } +bool seq_rewriter::reduce_contains(expr* a, expr* b, expr_ref_vector& disj) { + m_lhs.reset(); + m_util.str.get_concat(a, m_lhs); + TRACE("seq", tout << expr_ref(a, m()) << " " << expr_ref(b, m()) << "\n";); + zstring s; + for (unsigned i = 0; i < m_lhs.size(); ++i) { + expr* e = m_lhs.get(i); + if (m_util.str.is_empty(e)) { + continue; + } + + if (m_util.str.is_string(e, s)) { + unsigned sz = s.length(); + expr_ref_vector es(m()); + for (unsigned j = 0; j < sz; ++j) { + es.push_back(m_util.str.mk_char(s, j)); + } + es.append(m_lhs.size() - i, m_lhs.c_ptr() + i); + for (unsigned j = 0; j < sz; ++j) { + disj.push_back(m_util.str.mk_prefix(b, m_util.str.mk_concat(es.size() - j, es.c_ptr() + j))); + } + continue; + } + if (m_util.str.is_unit(e)) { + disj.push_back(m_util.str.mk_prefix(b, m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i))); + continue; + } + + if (m_util.str.is_string(b, s)) { + expr* all = m_util.re.mk_full_seq(m_util.re.mk_re(m().get_sort(b))); + std::cout << sort_ref(m().get_sort(all), m()) << "\n"; + disj.push_back(m_util.re.mk_in_re(m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i), + m_util.re.mk_concat(all, m_util.str.mk_concat(m_util.re.mk_to_re(b), all)))); + return true; + } + + if (i == 0) { + return false; + } + disj.push_back(m_util.str.mk_contains(m_util.str.mk_concat(m_lhs.size() - i, m_lhs.c_ptr() + i), b)); + return true; + } + disj.push_back(m().mk_eq(b, m_util.str.mk_empty(m().get_sort(b)))); + return true; +} + + expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) { SASSERT(n > 0); ptr_vector bs; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index c96096c65..f5878b2c2 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -168,6 +168,8 @@ public: bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& change); + bool reduce_contains(expr* a, expr* b, expr_ref_vector& disj); + void add_seqs(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 585dd0fa6..be3acc261 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1063,7 +1063,7 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg return; } if (num_indices > 0) - throw cmd_exception("invalid use of indexed indentifier, unknown builtin function ", s); + throw cmd_exception("invalid use of indexed identifier, unknown builtin function ", s); expr* _t; if (macros_find(s, num_args, args, _t)) { TRACE("macro_bug", tout << "well_sorted_check_enabled(): " << well_sorted_check_enabled() << "\n"; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index c71a6e21d..5267800db 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -401,11 +401,11 @@ namespace smt { label_hasher & m_lbl_hasher; func_decl * m_root_lbl; unsigned m_num_args; //!< we need this information to avoid the nary *,+ crash bug - unsigned char m_filter_candidates; + bool m_filter_candidates; unsigned m_num_regs; unsigned m_num_choices; instruction * m_root; - enode_vector m_candidates; + obj_hashtable m_candidates; #ifdef Z3DEBUG context * m_context; ptr_vector m_patterns; @@ -531,7 +531,7 @@ namespace smt { } bool filter_candidates() const { - return m_filter_candidates != 0; + return m_filter_candidates; } const instruction * get_root() const { @@ -539,7 +539,7 @@ namespace smt { } void add_candidate(enode * n) { - m_candidates.push_back(n); + m_candidates.insert(n); } bool has_candidates() const { @@ -550,7 +550,7 @@ namespace smt { m_candidates.reset(); } - enode_vector const & get_candidates() const { + obj_hashtable const & get_candidates() const { return m_candidates; } @@ -2001,7 +2001,9 @@ namespace smt { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); if (t->filter_candidates()) { + //t->display(std::cout << "ncf: " << t->get_candidates().size() << "\n"); for (enode* app : t->get_candidates()) { + TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (!app->is_marked() && app->is_cgr()) { if (m_context.resource_limits_exceeded() || !execute_core(t, app)) return; @@ -2014,6 +2016,9 @@ namespace smt { } } else { + //t->display(std::cout << "ncu: " << t->get_candidates().size() << "\n"); + //for (enode* app : t->get_candidates()) { std::cout << expr_ref(app->get_owner(), m_ast_manager) << "\n"; } + //std::cout.flush(); for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (app->is_cgr()) { @@ -3516,9 +3521,7 @@ namespace smt { std::cout << "Avg. " << static_cast(total_sz)/static_cast(counter) << ", Max. " << max_sz << "\n"; #endif - enode_vector::iterator it1 = v->begin(); - enode_vector::iterator end1 = v->end(); - for (; it1 != end1; ++it1) { + for (enode* n : *v) { // Two different kinds of mark are used: // - enode mark field: it is used to mark the already processed parents. // - enode mark2 field: it is used to mark the roots already added to be processed in the next level. @@ -3527,7 +3530,7 @@ namespace smt { // and Z3 may fail to find potential new matches. // // The file regression\acu.sx exposed this problem. - enode * curr_child = (*it1)->get_root(); + enode * curr_child = n->get_root(); if (m_use_filters && curr_child->get_plbls().empty_intersection(filter)) continue; @@ -3591,7 +3594,7 @@ namespace smt { is_eq(curr_tree->m_ground_arg, curr_parent->get_arg(curr_tree->m_ground_arg_idx)) )) { if (curr_tree->m_code) { - TRACE("mam_path_tree", tout << "found candidate\n";); + TRACE("mam_path_tree", tout << "found candidate " << expr_ref(curr_parent->get_owner(), m_ast_manager) << "\n";); add_candidate(curr_tree->m_code, curr_parent); } if (curr_tree->m_first_child) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 44147c668..aa7063dc1 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1351,18 +1351,9 @@ namespace smt { \remark The method assign_eq adds a new entry on this queue. */ bool context::propagate_eqs() { - for (unsigned i = 0; i < m_eq_propagation_queue.size(); i++) { + TRACE("add_eq", tout << m_eq_propagation_queue.size() << "\n";); + for (unsigned i = 0; i < m_eq_propagation_queue.size() && !get_cancel_flag(); i++) { new_eq & entry = m_eq_propagation_queue[i]; -#if 0 - static unsigned counter1 = 0; - static unsigned counter2 = 0; - if (entry.m_lhs->is_eq() || entry.m_rhs->is_eq()) - counter1++; - else - counter2++; - if ((counter1 + counter2) % 10000 == 0) - std::cout << counter1 << " " << counter2 << "\n"; -#endif add_eq(entry.m_lhs, entry.m_rhs, entry.m_justification); if (inconsistent()) return false; @@ -1376,7 +1367,7 @@ namespace smt { */ bool context::propagate_atoms() { SASSERT(!inconsistent()); - for (unsigned i = 0; i < m_atom_propagation_queue.size(); i++) { + for (unsigned i = 0; i < m_atom_propagation_queue.size() && !get_cancel_flag(); i++) { SASSERT(!inconsistent()); literal l = m_atom_propagation_queue[i]; bool_var v = l.var(); @@ -1558,16 +1549,17 @@ namespace smt { lbool context::get_assignment(expr * n) const { if (m_manager.is_false(n)) return l_false; - if (m_manager.is_not(n)) - return ~get_assignment_core(to_app(n)->get_arg(0)); + expr* arg = nullptr; + if (m_manager.is_not(n, arg)) + return ~get_assignment_core(arg); return get_assignment_core(n); } lbool context::find_assignment(expr * n) const { if (m_manager.is_false(n)) return l_false; - if (m_manager.is_not(n)) { - expr * arg = to_app(n)->get_arg(0); + expr* arg = nullptr; + if (m_manager.is_not(n, arg)) { if (b_internalized(arg)) return ~get_assignment_core(arg); return l_undef; @@ -1752,6 +1744,10 @@ namespace smt { return false; if (!propagate_eqs()) return false; + if (get_cancel_flag()) { + m_qhead = qhead; + return true; + } propagate_th_eqs(); propagate_th_diseqs(); if (inconsistent()) @@ -3264,6 +3260,7 @@ namespace smt { } void context::reset_assumptions() { + TRACE("unsat_core_bug", tout << "reset " << m_assumptions << "\n";); for (literal lit : m_assumptions) get_bdata(lit.var()).m_assumption = false; m_assumptions.reset(); @@ -4106,9 +4103,7 @@ namespace smt { } SASSERT(!inconsistent()); - unsigned sz = m_b_internalized_stack.size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = m_b_internalized_stack.get(i); + for (expr * curr : m_b_internalized_stack) { if (is_relevant(curr) && get_assignment(curr) == l_true) { // if curr is a label literal, then its tags will be copied to result. m_manager.is_label_lit(curr, result); @@ -4124,9 +4119,7 @@ namespace smt { void context::get_relevant_labeled_literals(bool at_lbls, expr_ref_vector & result) { SASSERT(!inconsistent()); buffer lbls; - unsigned sz = m_b_internalized_stack.size(); - for (unsigned i = 0; i < sz; i++) { - expr * curr = m_b_internalized_stack.get(i); + for (expr * curr : m_b_internalized_stack) { if (is_relevant(curr) && get_assignment(curr) == l_true) { lbls.reset(); if (m_manager.is_label_lit(curr, lbls)) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 2ac5695b3..b77f63e41 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -491,7 +491,7 @@ namespace smt { } bool tracking_assumptions() const { - return m_search_lvl > m_base_lvl; + return !m_assumptions.empty() && m_search_lvl > m_base_lvl; } expr * bool_var2expr(bool_var v) const { @@ -1011,6 +1011,7 @@ namespace smt { void push_eq(enode * lhs, enode * rhs, eq_justification const & js) { SASSERT(lhs != rhs); + SASSERT(lhs->get_root() != rhs->get_root()); m_eq_propagation_queue.push_back(new_eq(lhs, rhs, js)); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 48d4ddcc0..a906f0e6b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5163,7 +5163,21 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } } else if (m_util.str.is_contains(e, e1, e2)) { - if (is_true) { + expr_ref_vector disj(m); + if (m_seq_rewrite.reduce_contains(e1, e2, disj)) { + literal_vector lits; + literal lit = mk_literal(e); + lits.push_back(~lit); + for (expr* d : disj) { + lits.push_back(mk_literal(d)); + } + ++m_stats.m_add_axiom; + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + for (expr* d : disj) { + add_axiom(lit, ~mk_literal(d)); + } + } + else if (is_true) { expr_ref f1 = mk_skolem(m_indexof_left, e1, e2); expr_ref f2 = mk_skolem(m_indexof_right, e1, e2); f = mk_concat(f1, e2, f2); From d74978c2772fa5a474a6eb266ade720c613ecc64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 26 Jul 2018 20:29:26 +0100 Subject: [PATCH 072/118] fix #1762, #1764, #1768 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 -------- src/opt/opt_context.cpp | 8 +++----- src/smt/mam.cpp | 24 ++++++++++-------------- src/smt/params/theory_arith_params.h | 2 +- src/smt/theory_lra.cpp | 5 +++-- src/util/approx_nat.h | 2 +- src/util/bit_vector.cpp | 2 +- src/util/fixed_bit_vector.cpp | 2 +- src/util/hashtable.h | 4 ++-- src/util/lp/lar_solver.cpp | 8 ++++++-- src/util/memory_manager.cpp | 2 +- src/util/mpz.h | 1 - src/util/nat_set.h | 2 +- src/util/scoped_timer.cpp | 2 +- src/util/symbol.h | 2 +- 15 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 7711ec4cd..0eeeeaecc 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -1675,7 +1675,6 @@ def Or(*args): class PatternRef(ExprRef): """Patterns are hints for quantifier instantiation. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. """ def as_ast(self): return Z3_pattern_to_ast(self.ctx_ref(), self.ast) @@ -1686,8 +1685,6 @@ class PatternRef(ExprRef): def is_pattern(a): """Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> q = ForAll(x, f(x) == 0, patterns = [ f(x) ]) @@ -1705,8 +1702,6 @@ def is_pattern(a): def MultiPattern(*args): """Create a Z3 multi-pattern using the given expressions `*args` - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort()) >>> g = Function('g', IntSort(), IntSort()) >>> x = Int('x') @@ -1966,8 +1961,6 @@ def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') >>> y = Int('y') @@ -1985,7 +1978,6 @@ def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. - See http://rise4fun.com/Z3Py/tutorial/advanced for more details. >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 566aaa1f6..e5c0bcddb 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1012,8 +1012,7 @@ namespace opt { } } // fix types of objectives: - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective & obj = m_objectives[i]; + for (objective & obj : m_objectives) { expr* t = obj.m_term; switch(obj.m_type) { case O_MINIMIZE: @@ -1189,13 +1188,12 @@ namespace opt { void context::update_bound(bool is_lower) { expr_ref val(m); if (!m_model.get()) return; - for (unsigned i = 0; i < m_objectives.size(); ++i) { - objective const& obj = m_objectives[i]; + for (objective const& obj : m_objectives) { rational r; switch(obj.m_type) { case O_MINIMIZE: { val = (*m_model)(obj.m_term); - TRACE("opt", tout << obj.m_term << " " << val << " " << is_numeral(val, r) << "\n";); + TRACE("opt", tout << obj.m_term << " " << val << "\n";); if (is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); TRACE("opt", tout << "adjusted value: " << val << "\n";); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 5267800db..00e079989 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -405,7 +405,7 @@ namespace smt { unsigned m_num_regs; unsigned m_num_choices; instruction * m_root; - obj_hashtable m_candidates; + enode_vector m_candidates; #ifdef Z3DEBUG context * m_context; ptr_vector m_patterns; @@ -539,7 +539,7 @@ namespace smt { } void add_candidate(enode * n) { - m_candidates.insert(n); + m_candidates.push_back(n); } bool has_candidates() const { @@ -550,7 +550,7 @@ namespace smt { m_candidates.reset(); } - obj_hashtable const & get_candidates() const { + enode_vector const & get_candidates() const { return m_candidates; } @@ -1978,10 +1978,10 @@ namespace smt { #define INIT_ARGS_SIZE 16 public: - interpreter(context & ctx, mam & m, bool use_filters): + interpreter(context & ctx, mam & ma, bool use_filters): m_context(ctx), m_ast_manager(ctx.get_manager()), - m_mam(m), + m_mam(ma), m_use_filters(use_filters) { m_args.resize(INIT_ARGS_SIZE); } @@ -2001,7 +2001,6 @@ namespace smt { TRACE("trigger_bug", tout << "execute for code tree:\n"; t->display(tout);); init(t); if (t->filter_candidates()) { - //t->display(std::cout << "ncf: " << t->get_candidates().size() << "\n"); for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (!app->is_marked() && app->is_cgr()) { @@ -2016,9 +2015,6 @@ namespace smt { } } else { - //t->display(std::cout << "ncu: " << t->get_candidates().size() << "\n"); - //for (enode* app : t->get_candidates()) { std::cout << expr_ref(app->get_owner(), m_ast_manager) << "\n"; } - //std::cout.flush(); for (enode* app : t->get_candidates()) { TRACE("trigger_bug", tout << "candidate\n" << mk_ismt2_pp(app->get_owner(), m_ast_manager) << "\n";); if (app->is_cgr()) { @@ -2842,7 +2838,7 @@ namespace smt { mk_tree_trail(ptr_vector & t, unsigned id):m_trees(t), m_lbl_id(id) {} void undo(mam_impl & m) override { dealloc(m_trees[m_lbl_id]); - m_trees[m_lbl_id] = 0; + m_trees[m_lbl_id] = nullptr; } }; @@ -2875,8 +2871,8 @@ namespace smt { app * p = to_app(mp->get_arg(first_idx)); func_decl * lbl = p->get_decl(); unsigned lbl_id = lbl->get_decl_id(); - m_trees.reserve(lbl_id+1, 0); - if (m_trees[lbl_id] == 0) { + m_trees.reserve(lbl_id+1, nullptr); + if (m_trees[lbl_id] == nullptr) { m_trees[lbl_id] = m_compiler.mk_tree(qa, mp, first_idx, false); SASSERT(m_trees[lbl_id]->expected_num_args() == p->get_num_args()); DEBUG_CODE(m_trees[lbl_id]->set_context(m_context);); @@ -2961,7 +2957,7 @@ namespace smt { m_ground_arg(ground_arg), m_pattern_idx(pat_idx), m_child(child) { - SASSERT(ground_arg != 0 || ground_arg_idx == 0); + SASSERT(ground_arg != nullptr || ground_arg_idx == 0); } }; @@ -3228,7 +3224,7 @@ namespace smt { path_tree * mk_path_tree(path * p, quantifier * qa, app * mp) { SASSERT(m_ast_manager.is_pattern(mp)); - SASSERT(p != 0); + SASSERT(p != nullptr); unsigned pat_idx = p->m_pattern_idx; path_tree * head = nullptr; path_tree * curr = nullptr; diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 9d09b4c38..fe7cc6060 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_ARITH_PARAMS_H_ #define THEORY_ARITH_PARAMS_H_ -#include +#include #include "util/params.h" enum arith_solver_id { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index a057ace03..2f89b7168 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2648,6 +2648,7 @@ public: else { rational r = get_value(v); TRACE("arith", tout << "v" << v << " := " << r << "\n";); + SASSERT(!a.is_int(o) || r.is_int()); if (a.is_int(o) && !r.is_int()) r = floor(r); return alloc(expr_wrapper_proc, m_factory->mk_value(r, m.get_sort(o))); } @@ -2797,6 +2798,7 @@ public: lp::var_index vi = m_theory_var2var_index[v]; st = m_solver->maximize_term(vi, term_max); } + TRACE("arith", display(tout << st << " v" << v << "\n");); switch (st) { case lp::lp_status::OPTIMAL: { inf_rational val(term_max.x, term_max.y); @@ -2804,13 +2806,12 @@ public: return inf_eps(rational::zero(), val); } case lp::lp_status::FEASIBLE: { - inf_rational val(term_max.x, term_max.y); + inf_rational val = get_value(v); blocker = mk_gt(v); return inf_eps(rational::zero(), val); } default: SASSERT(st == lp::lp_status::UNBOUNDED); - TRACE("arith", tout << "Unbounded v" << v << "\n";); has_shared = false; blocker = m.mk_false(); return inf_eps(rational::one(), inf_rational()); diff --git a/src/util/approx_nat.h b/src/util/approx_nat.h index b5e1edb8f..be5fc4fb6 100644 --- a/src/util/approx_nat.h +++ b/src/util/approx_nat.h @@ -21,7 +21,7 @@ Notes: #define APPROX_NAT_H_ #include -#include +#include class approx_nat { unsigned m_value; diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index f9f0a0797..78b7f15aa 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ -#include +#include #include "util/bit_vector.h" #include "util/trace.h" diff --git a/src/util/fixed_bit_vector.cpp b/src/util/fixed_bit_vector.cpp index aafc58404..e227aa524 100644 --- a/src/util/fixed_bit_vector.cpp +++ b/src/util/fixed_bit_vector.cpp @@ -19,7 +19,7 @@ Revision History: --*/ -#include +#include #include "util/fixed_bit_vector.h" #include "util/trace.h" #include "util/hash.h" diff --git a/src/util/hashtable.h b/src/util/hashtable.h index 420e48949..55866065e 100644 --- a/src/util/hashtable.h +++ b/src/util/hashtable.h @@ -19,9 +19,9 @@ Revision History: #ifndef HASHTABLE_H_ #define HASHTABLE_H_ #include "util/debug.h" -#include +#include #include "util/util.h" -#include +#include #include "util/memory_manager.h" #include "util/hash.h" #include "util/vector.h" diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 041b49389..13ef79a96 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -538,12 +538,16 @@ lp_status lar_solver::maximize_term(unsigned ext_j, if (column_value_is_integer(j)) continue; if (m_int_solver->is_base(j)) { - if (!remove_from_basis(j)) // consider a special version of remove_from_basis that would not remove inf_int columns + if (!remove_from_basis(j)) { // consider a special version of remove_from_basis that would not remove inf_int columns + m_mpq_lar_core_solver.m_r_x = backup; return lp_status::FEASIBLE; // it should not happen + } } m_int_solver->patch_nbasic_column(j, false); - if (!column_value_is_integer(j)) + if (!column_value_is_integer(j)) { + m_mpq_lar_core_solver.m_r_x = backup; return lp_status::FEASIBLE; + } change = true; } if (change) { diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index 59a6cb009..0a1d360c8 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -6,7 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include #include -#include +#include #include "util/trace.h" #include "util/memory_manager.h" #include "util/error_codes.h" diff --git a/src/util/mpz.h b/src/util/mpz.h index 187532a87..65f89f078 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -19,7 +19,6 @@ Revision History: #ifndef MPZ_H_ #define MPZ_H_ -#include #include #include "util/util.h" #include "util/small_object_allocator.h" diff --git a/src/util/nat_set.h b/src/util/nat_set.h index 6e9ab1b6d..f2f2cb8e1 100644 --- a/src/util/nat_set.h +++ b/src/util/nat_set.h @@ -19,7 +19,7 @@ Revision History: #ifndef NAT_SET_H_ #define NAT_SET_H_ -#include +#include #include "util/vector.h" class nat_set { diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 56d40c47a..8078c46ee 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -50,7 +50,7 @@ Revision History: #undef max #endif #include "util/util.h" -#include +#include #include "util/z3_omp.h" struct scoped_timer::imp { diff --git a/src/util/symbol.h b/src/util/symbol.h index 88e825551..40844cf3b 100644 --- a/src/util/symbol.h +++ b/src/util/symbol.h @@ -19,7 +19,7 @@ Revision History: #ifndef SYMBOL_H_ #define SYMBOL_H_ #include -#include +#include #include "util/util.h" #include "util/tptr.h" From ef2cdc226aba110804187c94bffd75c515243752 Mon Sep 17 00:00:00 2001 From: Lev Date: Thu, 26 Jul 2018 22:46:28 -0700 Subject: [PATCH 073/118] a fix in maximize_term Signed-off-by: Lev --- src/util/lp/int_solver.h | 1 - src/util/lp/lar_solver.cpp | 5 ++++- src/util/lp/lia_move.h | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 65c818d1e..ec708918d 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -50,7 +50,6 @@ public: // main function to check that the solution provided by lar_solver is valid for integral values, // or provide a way of how it can be adjusted. lia_move check(lar_term& t, mpq& k, explanation& ex, bool & upper); - lia_move check_(lar_term& t, mpq& k, explanation& ex, bool & upper); bool move_non_basic_column_to_bounds(unsigned j); lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex); bool is_base(unsigned j) const; diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 041b49389..0cfdc33b4 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -542,8 +542,11 @@ lp_status lar_solver::maximize_term(unsigned ext_j, return lp_status::FEASIBLE; // it should not happen } m_int_solver->patch_nbasic_column(j, false); - if (!column_value_is_integer(j)) + if (!column_value_is_integer(j)) { + term_max = prev_value; + m_mpq_lar_core_solver.m_r_x = backup; return lp_status::FEASIBLE; + } change = true; } if (change) { diff --git a/src/util/lp/lia_move.h b/src/util/lp/lia_move.h index ec4643e20..65da5826e 100644 --- a/src/util/lp/lia_move.h +++ b/src/util/lp/lia_move.h @@ -28,4 +28,25 @@ enum class lia_move { undef, unsat }; +inline std::string lia_move_to_string(lia_move m) { + switch (m) { + case lia_move::sat: + return "sat"; + case lia_move::branch: + return "branch"; + case lia_move::cut: + return "cut"; + case lia_move::conflict: + return "conflict"; + case lia_move::continue_with_check: + return "continue_with_check"; + case lia_move::undef: + return "undef"; + case lia_move::unsat: + return "unsat"; + default: + lp_assert(false); + }; + return "strange"; +} } From a91531c04c7a0dd184f8b7b3111314f63b629959 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 17:54:32 -0700 Subject: [PATCH 074/118] Stub z3test.py for pydistrib --- src/api/python/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 24ba59ac2..a2b312e6d 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -118,6 +118,7 @@ def _copy_sources(): os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python')) os.mkdir(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3')) open(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3', '.placeholder'), 'w').close() + open(os.path.join(SRC_DIR_LOCAL, 'src', 'api', 'python', 'z3test.py'), 'w').close() class build(_build): def run(self): From 64eaf6cb01cce2dc8302abc11f714df1a7aa9a43 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 17:55:02 -0700 Subject: [PATCH 075/118] Add bdist_wheel tag renaming blurb --- src/api/python/setup.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index a2b312e6d..bc383c632 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -6,6 +6,7 @@ import subprocess import multiprocessing import re from setuptools import setup +from distutils.util import get_platform from distutils.errors import LibError from distutils.command.build import build as _build from distutils.command.sdist import sdist as _sdist @@ -149,6 +150,26 @@ class sdist(_sdist): #try: os.makedirs(os.path.join(ROOT_DIR, 'build')) #except OSError: pass +if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: + idx = sys.argv.index('bdist_wheel') + 1 + sys.argv.insert(idx, '--plat-name') + name = get_platform() + if 'linux' in name: + # linux_* platform tags are disallowed because the python ecosystem is fubar + # linux builds should be built in the centos 5 vm for maximum compatibility + # see https://github.com/pypa/manylinux + # see also https://github.com/angr/angr-dev/blob/master/bdist.sh + sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine()) + elif 'mingw' in name: + if platform.architecture()[0] == '64bit': + sys.argv.insert(idx + 1, 'win_amd64') + else: + sys.argv.insert(idx + 1, 'win32') + else: + # https://www.python.org/dev/peps/pep-0425/ + sys.argv.insert(idx + 1, name.replace('.', '_').replace('-', '_')) + + setup( name='z3-solver', version=_z3_version(), From 42af36563e98c52f37a2a741c483efbf41a594b3 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 17:55:16 -0700 Subject: [PATCH 076/118] Autogenerate list of header files --- src/api/python/setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index bc383c632..c9e7ea9f4 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -98,7 +98,10 @@ def _copy_bins(): os.mkdir(os.path.join(HEADERS_DIR, 'c++')) shutil.copy(os.path.join(BUILD_DIR, LIBRARY_FILE), LIBS_DIR) shutil.copy(os.path.join(BUILD_DIR, EXECUTABLE_FILE), BINS_DIR) - for fname in ('z3.h', 'z3_v1.h', 'z3_macros.h', 'z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h', os.path.join('c++', 'z3++.h')): + + header_files = [x for x in os.listdir(os.path.join(SRC_DIR, 'src', 'api')) if x.endswith('.h')] + header_files += [os.path.join('c++', x) for x in os.listdir(os.path.join(SRC_DIR, 'src', 'api', 'c++')) if x.endswith('.h')] + for fname in header_files: shutil.copy(os.path.join(SRC_DIR, 'src', 'api', fname), os.path.join(HEADERS_DIR, fname)) def _copy_sources(): From a7f7872f45584dbd7848fa0c4043eac9b7c4a11d Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 18:05:58 -0700 Subject: [PATCH 077/118] Update maintainer info --- src/api/python/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index c9e7ea9f4..07fc6e866 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -179,8 +179,8 @@ setup( description='an efficient SMT solver library', long_description='Z3 is a theorem prover from Microsoft Research with support for bitvectors, booleans, arrays, floating point numbers, strings, and other data types.\n\nFor documentation, please read http://z3prover.github.io/api/html/z3.html\n\nIn the event of technical difficulties related to configuration, compiliation, or installation, please submit issues to https://github.com/angr/angr-z3', author="The Z3 Theorem Prover Project", - maintainer="Andrew Dutcher", - maintainer_email="andrew@andrewdutcher.com", + maintainer="Audrey Dutcher", + maintainer_email="audrey@rhelmot.io", url='https://github.com/Z3Prover/z3', license='MIT License', keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], From d74edbcb2b7342743a32b0829b2a6e3cf35cf5a6 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 18:11:11 -0700 Subject: [PATCH 078/118] Add environment variable for controlling version suffixes --- src/api/python/setup.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 07fc6e866..0aed1e5ab 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -46,13 +46,14 @@ def _clean_bins(): shutil.rmtree(HEADERS_DIR, ignore_errors=True) def _z3_version(): + post = os.getenv('Z3_VERSION_SUFFIX', '') fn = os.path.join(SRC_DIR, 'scripts', 'mk_project.py') - if os.path.exists(fn): + if os.path.exists(fn): with open(fn) as f: for line in f: n = re.match(".*set_version\((.*), (.*), (.*), (.*)\).*", line) if not n is None: - return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4) + return n.group(1) + '.' + n.group(2) + '.' + n.group(3) + '.' + n.group(4) + post return "?.?.?.?" def _configure_z3(): From 310de49d2b646105114f8e8761cbf0f9e7972b03 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Sat, 28 Jul 2018 18:56:40 -0700 Subject: [PATCH 079/118] Update link to reference high-compatibility build script --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 0aed1e5ab..bce681584 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -162,7 +162,7 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: # linux_* platform tags are disallowed because the python ecosystem is fubar # linux builds should be built in the centos 5 vm for maximum compatibility # see https://github.com/pypa/manylinux - # see also https://github.com/angr/angr-dev/blob/master/bdist.sh + # see also https://github.com/angr/angr-dev/blob/master/admin/bdist.py sys.argv.insert(idx + 1, 'manylinux1_' + platform.machine()) elif 'mingw' in name: if platform.architecture()[0] == '64bit': From 879e217fe69d3c95f99f9ca813b075a72c004950 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 28 Jul 2018 20:28:53 -0700 Subject: [PATCH 080/118] limits -> climits Signed-off-by: Nikolaj Bjorner --- src/util/approx_nat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/approx_nat.h b/src/util/approx_nat.h index be5fc4fb6..354ead92b 100644 --- a/src/util/approx_nat.h +++ b/src/util/approx_nat.h @@ -21,7 +21,7 @@ Notes: #define APPROX_NAT_H_ #include -#include +#include class approx_nat { unsigned m_value; From 5380b01fd171cd2bc804b46c10027fb53e7994d9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Jul 2018 00:44:40 -0700 Subject: [PATCH 081/118] bool -> string Signed-off-by: Nikolaj Bjorner --- src/api/api_numeral.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 4d0009fbe..2b77294d5 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -186,7 +186,7 @@ extern "C" { // This function invokes Z3_get_numeral_rational, but it is still ok to add LOG command here because it does not return a Z3 object. LOG_Z3_get_numeral_string(c, a); RESET_ERROR_CODE(); - CHECK_IS_EXPR(a, Z3_FALSE); + CHECK_IS_EXPR(a, ""); rational r; Z3_bool ok = Z3_get_numeral_rational(c, a, r); if (ok == Z3_TRUE) { From 64e570f1592f3e0007ca9fab84e39f2de2e44a3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Jul 2018 02:22:28 -0700 Subject: [PATCH 082/118] fix #1766 Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_core.h | 44 ++----------------------------------- src/smt/theory_bv.cpp | 2 ++ src/smt/theory_seq.cpp | 3 ++- 3 files changed, 6 insertions(+), 43 deletions(-) diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 01eb8a3d4..54f61a09a 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -2943,29 +2943,9 @@ namespace smt { context & ctx = get_context(); if (dump_lemmas()) { TRACE("arith", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); - unsigned id = ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), + ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), l); -#if 1 - if (id == 394) { - enable_trace("sign_row_conflict"); - enable_trace("nl_arith_bug"); - enable_trace("nl_evaluate"); - enable_trace("propagate_bounds"); - enable_trace("propagate_bounds_bug"); - enable_trace("arith_conflict"); - enable_trace("non_linear"); - enable_trace("non_linear_bug"); - } - SASSERT(id != 395); - if (id == 396) { - disable_trace("nl_arith_bug"); - disable_trace("propagate_bounds"); - disable_trace("arith_conflict"); - disable_trace("non_linear"); - disable_trace("non_linear_bug"); - } -#endif } } @@ -2973,28 +2953,8 @@ namespace smt { void theory_arith::dump_lemmas(literal l, derived_bound const& ante) { context & ctx = get_context(); if (dump_lemmas()) { - unsigned id = ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), + ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), l); -#if 1 - if (id == 394) { - enable_trace("nl_arith_bug"); - enable_trace("nl_evaluate"); - enable_trace("propagate_bounds"); - enable_trace("arith_conflict"); - enable_trace("propagate_bounds_bug"); - enable_trace("non_linear"); - enable_trace("non_linear_bug"); - } - SASSERT(id != 395); - if (id == 396) { - enable_trace("sign_row_conflict"); - disable_trace("nl_arith_bug"); - disable_trace("propagate_bounds"); - disable_trace("arith_conflict"); - disable_trace("non_linear"); - disable_trace("non_linear_bug"); - } -#endif } } diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 261881a3b..a0c62b959 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -161,6 +161,8 @@ namespace smt { theory_var v = n->get_th_var(get_id()); if (v == null_theory_var) { v = mk_var(n); + } + if (m_bits[v].empty()) { mk_bits(v); } return v; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4c0e9b87d..d6937aa79 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -5163,7 +5163,8 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { } else if (m_util.str.is_contains(e, e1, e2)) { expr_ref_vector disj(m); - if (m_seq_rewrite.reduce_contains(e1, e2, disj)) { + // disabled pending regression on issue 1196 + if (false && m_seq_rewrite.reduce_contains(e1, e2, disj)) { literal_vector lits; literal lit = mk_literal(e); lits.push_back(~lit); From 5509bf248aa1270083552292d7da3dc6fd21cca5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Jul 2018 08:02:56 -0700 Subject: [PATCH 083/118] coallesce lambda/quant tracing Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 17 +++++++++++------ src/smt/theory_seq.cpp | 2 -- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 74166a78b..5fcc8d63b 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2369,6 +2369,15 @@ bool ast_manager::is_pattern(expr const * n, ptr_vector &args) { return true; } +static void trace_quant(std::ostream& strm, quantifier* q) { + strm << (is_lambda(q) ? "[mk-lambda]" : "[mk-quant]") + << " #" << q->get_id() << " " << q->get_qid(); + for (unsigned i = 0; i < q->get_num_patterns(); ++i) { + strm << " #" << q->get_pattern(i)->get_id(); + } + strm << " #" << q->get_expr()->get_id() << "\n"; +} + quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, sort * const * decl_sorts, symbol const * decl_names, expr * body, int weight , symbol const & qid, symbol const & skid, @@ -2401,11 +2410,7 @@ quantifier * ast_manager::mk_quantifier(quantifier_kind k, unsigned num_decls, s quantifier * r = register_node(new_node); if (m_trace_stream && r == new_node) { - *m_trace_stream << "[mk-quant] #" << r->get_id() << " " << qid; - for (unsigned i = 0; i < num_patterns; ++i) { - *m_trace_stream << " #" << patterns[i]->get_id(); - } - *m_trace_stream << " #" << body->get_id() << "\n"; + trace_quant(*m_trace_stream, r); } return r; @@ -2420,7 +2425,7 @@ quantifier * ast_manager::mk_lambda(unsigned num_decls, sort * const * decl_sort quantifier * new_node = new (mem) quantifier(num_decls, decl_sorts, decl_names, body, s); quantifier * r = register_node(new_node); if (m_trace_stream && r == new_node) { - *m_trace_stream << "[mk-lambda] #" << r->get_id() << ": #" << body->get_id() << "\n"; + trace_quant(*m_trace_stream, r); } return r; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d6937aa79..8f64544b4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -4581,7 +4581,6 @@ bool theory_seq::lower_bound(expr* _e, rational& lo) const { if (thi && thi->get_lower(ctx.get_enode(e), _lo)) break; theory_lra* thr = get_th_arith(ctx, afid, e); if (thr && thr->get_lower(ctx.get_enode(e), _lo)) break; - TRACE("seq", tout << "no lower bound " << mk_pp(_e, m) << "\n";); return false; } while (false); @@ -4639,7 +4638,6 @@ bool theory_seq::upper_bound(expr* _e, rational& hi) const { if (thi && thi->get_upper(ctx.get_enode(e), _hi)) break; theory_lra* thr = get_th_arith(ctx, afid, e); if (thr && thr->get_upper(ctx.get_enode(e), _hi)) break; - TRACE("seq", tout << "no upper bound " << mk_pp(_e, m) << "\n";); return false; } while (false); From 13390e2c3a821417a21ed8d53eb789db074a4bfd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Jul 2018 12:08:59 -0700 Subject: [PATCH 084/118] fix #681, unsound propagation of binary equalities. Clean up memory leaks on exit Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 1 + src/smt/theory_seq.cpp | 94 +++++++++++++++++++----------------------- src/smt/theory_seq.h | 10 ++--- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5fcc8d63b..5a14a64c0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1715,6 +1715,7 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); + TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 8f64544b4..b00c1565c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -367,7 +367,7 @@ bool theory_seq::branch_binary_variable(eq const& e) { return false; } ptr_vector xs, ys; - expr* x, *y; + expr_ref x(m), y(m); bool is_binary = is_binary_eq(e.ls(), e.rs(), x, xs, ys, y); if (!is_binary) { is_binary = is_binary_eq(e.rs(), e.ls(), x, xs, ys, y); @@ -630,7 +630,7 @@ bool theory_seq::branch_ternary_variable_base( // Equation is of the form x ++ xs = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_ternary_variable(eq const& e, bool flag1) { expr_ref_vector xs(m), ys(m); - expr* x = nullptr, *y1 = nullptr, *y2 = nullptr; + expr_ref x(m), y1(m), y2(m); bool is_ternary = is_ternary_eq(e.ls(), e.rs(), x, xs, y1, ys, y2, flag1); if (!is_ternary) { is_ternary = is_ternary_eq(e.rs(), e.ls(), x, xs, y1, ys, y2, flag1); @@ -746,7 +746,7 @@ bool theory_seq::branch_ternary_variable_base2(dependency* dep, unsigned_vector // Equation is of the form xs ++ x = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_ternary_variable2(eq const& e, bool flag1) { expr_ref_vector xs(m), ys(m); - expr* x = nullptr, *y1 = nullptr, *y2 = nullptr; + expr_ref x(m), y1(m), y2(m); bool is_ternary = is_ternary_eq2(e.ls(), e.rs(), xs, x, y1, ys, y2, flag1); if (!is_ternary) { is_ternary = is_ternary_eq2(e.rs(), e.ls(), xs, x, y1, ys, y2, flag1); @@ -823,7 +823,7 @@ bool theory_seq::branch_quat_variable() { // Equation is of the form x1 ++ xs ++ x2 = y1 ++ ys ++ y2 where xs, ys are units. bool theory_seq::branch_quat_variable(eq const& e) { expr_ref_vector xs(m), ys(m); - expr* x1_l = nullptr, *x2 = nullptr, *y1_l = nullptr, *y2 = nullptr; + expr_ref x1_l(m), x2(m), y1_l(m), y2(m); bool is_quat = is_quat_eq(e.ls(), e.rs(), x1_l, xs, x2, y1_l, ys, y2); if (!is_quat) { return false; @@ -1080,8 +1080,8 @@ void theory_seq::find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector cons } // TODO: propagate length offsets for last vars -bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned const& idx, - dependency*& deps, expr_ref_vector & res) { +bool theory_seq::find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx, + dependency*& deps, expr_ref_vector & res) { context& ctx = get_context(); if (ls.empty() || rs.empty()) @@ -2262,6 +2262,7 @@ bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependenc SASSERT(lhs.size() == rhs.size()); m_seq_rewrite.add_seqs(ls, rs, lhs, rhs); if (lhs.empty()) { + TRACE("seq", tout << "solved\n";); return true; } TRACE("seq", @@ -2411,6 +2412,7 @@ bool theory_seq::solve_eqs(unsigned i) { m_eqs.pop_back(); change = true; } + TRACE("seq", display_equations(tout);); } return change || m_new_propagation || ctx.inconsistent(); } @@ -2429,6 +2431,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de display_deps(tout, deps); ); if (!ctx.inconsistent() && simplify_eq(ls, rs, deps)) { + TRACE("seq", tout << "simplified\n";); return true; } TRACE("seq", tout << ls << " = " << rs << "\n";); @@ -2464,6 +2467,7 @@ bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, de if (!updated) { m_eqs.push_back(eq(m_eq_id++, ls, rs, deps)); } + TRACE("seq", tout << "simplified\n";); return true; } return false; @@ -2483,7 +2487,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { return false; } -bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { +bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, ptr_vector& xs, ptr_vector& ys, expr_ref& y) { if (ls.size() > 1 && is_var(ls[0]) && rs.size() > 1 && is_var(rs.back())) { xs.reset(); @@ -2504,7 +2508,7 @@ bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& } bool theory_seq::is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, -expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr*& y2) { + expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2) { if (ls.size() > 1 && is_var(ls[0]) && is_var(ls.back()) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = 1; @@ -2547,7 +2551,7 @@ expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr* } bool theory_seq::is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, -expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1) { + expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1) { if (ls.size() > 1 && (is_var(ls[0]) || flag1) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = ls.size()-1; @@ -2585,7 +2589,7 @@ expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool f } bool theory_seq::is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, - expr_ref_vector& xs, expr*& x, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1) { + expr_ref_vector& xs, expr_ref& x, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1) { if (ls.size() > 1 && (is_var(ls.back()) || flag1) && rs.size() > 1 && is_var(rs[0]) && is_var(rs.back())) { unsigned l_start = 0; @@ -2747,7 +2751,7 @@ bool theory_seq::reduce_length(unsigned i, unsigned j, bool front, expr_ref_vect bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) { context& ctx = get_context(); ptr_vector xs, ys; - expr* x, *y; + expr_ref x(m), y(m); bool is_binary = is_binary_eq(ls, rs, x, xs, ys, y); if (!is_binary) { is_binary = is_binary_eq(rs, ls, x, xs, ys, y); @@ -2770,49 +2774,36 @@ bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector cons UNREACHABLE(); return false; } - unsigned sz = xs.size(); - literal_vector conflict; - for (unsigned offset = 0; offset < sz; ++offset) { - bool has_conflict = false; - for (unsigned j = 0; !has_conflict && j < sz; ++j) { - unsigned j1 = (offset + j) % sz; - if (xs[j] == ys[j1]) continue; - literal eq = mk_eq(xs[j], ys[j1], false); - switch (ctx.get_assignment(eq)) { - case l_false: - conflict.push_back(~eq); - has_conflict = true; - break; - case l_undef: { - enode* n1 = ensure_enode(xs[j]); - enode* n2 = ensure_enode(ys[j1]); - if (n1->get_root() == n2->get_root()) { - break; - } - ctx.mark_as_relevant(eq); - if (sz == 1) { - propagate_lit(dep, 0, nullptr, eq); - return true; - } - m_new_propagation = true; - break; - } - case l_true: - break; - } - } - if (!has_conflict) { - TRACE("seq", tout << "offset: " << offset << " equality "; - for (unsigned j = 0; j < sz; ++j) { - tout << mk_pp(xs[j], m) << " = " << mk_pp(ys[(offset+j) % sz], m) << "; "; - } - tout << "\n";); - // current equalities can work when solving x ++ xs = ys ++ y + + // Equation is of the form x ++ xs = ys ++ x + // where |xs| = |ys| are units of same length + // then xs is a wrap-around of ys + // x ++ ab = ba ++ x + // + if (xs.size() == 1) { + enode* n1 = ensure_enode(xs[0]); + enode* n2 = ensure_enode(ys[0]); + if (n1->get_root() == n2->get_root()) { return false; } + literal eq = mk_eq(xs[0], ys[0], false); + switch (ctx.get_assignment(eq)) { + case l_false: { + literal_vector conflict; + conflict.push_back(~eq); + TRACE("seq", tout << conflict << "\n";); + set_conflict(dep, conflict); + break; + } + case l_true: + break; + case l_undef: + ctx.mark_as_relevant(eq); + propagate_lit(dep, 0, nullptr, eq); + m_new_propagation = true; + break; + } } - TRACE("seq", tout << conflict << "\n";); - set_conflict(dep, conflict); return false; } @@ -5248,6 +5239,7 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { } void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { + TRACE("seq", tout << expr_ref(n1->get_owner(), m) << " = " << expr_ref(n2->get_owner(), m) << "\n";); if (n1 != n2 && m_util.is_seq(n1->get_owner())) { theory_var v1 = n1->get_th_var(get_id()); theory_var v2 = n2->get_th_var(get_id()); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 23b044445..fbefaede2 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -381,7 +381,7 @@ namespace smt { expr* find_fst_non_empty_var(expr_ref_vector const& x) const; void find_max_eq_len(expr_ref_vector const& ls, expr_ref_vector const& rs); bool has_len_offset(expr_ref_vector const& ls, expr_ref_vector const& rs, int & diff); - bool find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned const& idx, dependency*& deps, expr_ref_vector & res); + bool find_better_rep(expr_ref_vector const& ls, expr_ref_vector const& rs, unsigned idx, dependency*& deps, expr_ref_vector & res); // final check bool simplify_and_solve_eqs(); // solve unitary equalities @@ -427,10 +427,10 @@ namespace smt { bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); bool solve_unit_eq(expr* l, expr* r, dependency* dep); bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); - bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); - bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x1, expr_ref_vector& xs, expr*& x2, expr*& y1, expr_ref_vector& ys, expr*& y2); - bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, expr_ref_vector& xs, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1); - bool is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& xs, expr*& x, expr*& y1, expr_ref_vector& ys, expr*& y2, bool flag1); + bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr_ref& x, ptr_vector& xunits, ptr_vector& yunits, expr_ref& y); + bool is_quat_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x1, expr_ref_vector& xs, expr_ref& x2, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2); + bool is_ternary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref& x, expr_ref_vector& xs, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); + bool is_ternary_eq2(expr_ref_vector const& ls, expr_ref_vector const& rs, expr_ref_vector& xs, expr_ref& x, expr_ref& y1, expr_ref_vector& ys, expr_ref& y2, bool flag1); bool solve_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); bool propagate_max_length(expr* l, expr* r, dependency* dep); From 16b71fe911a706c3b14d495bca3577ff58a5c247 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 18 Jul 2018 12:50:54 -0700 Subject: [PATCH 085/118] work on static_matrix's cells Signed-off-by: Lev trying the new scheme in static_matrix : in progress Signed-off-by: Lev Nachmanson in the middle of changes in static_matrix Signed-off-by: Lev Nachmanson more fixes in static_matrix.h Signed-off-by: Lev Nachmanson debug Signed-off-by: Lev Nachmanson fixes in static_matrix Signed-off-by: Lev fixes in static_matrix, column_strip Signed-off-by: Lev fixes in static_matrix Signed-off-by: Lev Nachmanson fixes for static_matrix Signed-off-by: Lev work on static_matrix Signed-off-by: Lev work on static_matrix Signed-off-by: Lev progress in static_matrix Signed-off-by: Lev fix a bug in swap_with_head_cell Signed-off-by: Lev progress in static_matrix Signed-off-by: Lev compress rows and columns if needed Signed-off-by: Lev fix in compression of cells Signed-off-by: Lev Nachmanson --- src/shell/main.cpp | 8 +- src/tactic/smtlogics/qflia_tactic.cpp | 4 + src/test/lp/lp.cpp | 2 +- src/util/lp/bound_analyzer_on_row.h | 70 +-- src/util/lp/bound_propagator.cpp | 2 + src/util/lp/core_solver_pretty_printer_def.h | 2 +- src/util/lp/indexed_vector.h | 1 + src/util/lp/int_solver.cpp | 17 +- src/util/lp/lar_core_solver.h | 10 +- src/util/lp/lar_core_solver_def.h | 5 +- src/util/lp/lar_solver.cpp | 66 ++- src/util/lp/lp_core_solver_base.h | 18 +- src/util/lp/lp_core_solver_base_def.h | 91 +-- src/util/lp/lp_primal_core_solver.h | 62 +- src/util/lp/lp_primal_core_solver_def.h | 2 +- .../lp/lp_primal_core_solver_tableau_def.h | 22 +- src/util/lp/lu.h | 4 +- src/util/lp/lu_def.h | 2 +- src/util/lp/random_updater_def.h | 5 +- src/util/lp/static_matrix.cpp | 9 +- src/util/lp/static_matrix.h | 549 +++++++++++++++--- src/util/lp/static_matrix_def.h | 204 +++---- 22 files changed, 767 insertions(+), 388 deletions(-) diff --git a/src/shell/main.cpp b/src/shell/main.cpp index d367b8ec6..f6c809bb2 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -295,7 +295,13 @@ void parse_cmd_line_args(int argc, char ** argv) { int STD_CALL main(int argc, char ** argv) { - try{ +#ifdef DUMP_ARGS + std::cout << "args are: "; + for (int i = 0; i < argc; i++) + std::cout << argv[i] <<" "; + std::cout << std::endl; +#endif + try{ unsigned return_value = 0; memory::initialize(0); memory::exit_when_out_of_memory(true, "ERROR: out of memory"); diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index eed4e4425..ad5b660c3 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -212,6 +212,9 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(preamble_st, +#if 1 + mk_smt_tactic()), +#else or_else(mk_ilp_model_finder_tactic(m), mk_pb_tactic(m), and_then(fail_if_not(mk_is_quasi_pb_probe()), @@ -219,6 +222,7 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), mk_smt_tactic())), +#endif main_p); diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 6e418fe68..37a096827 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2541,7 +2541,7 @@ void read_row_cols(unsigned i, static_matrix& A, std::ifstream & lp_assert(r.size() == 4); unsigned j = atoi(r[1].c_str()); double v = atof(r[3].c_str()); - A.set(i, j, v); + A.add_new_element(i, j, v); } while (true); } diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 196551f20..3d047cd86 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -29,65 +29,7 @@ Revision History: namespace lp { template // C plays a role of a container class bound_analyzer_on_row { - struct term_with_basis_col { - const C & m_row; - unsigned m_bj; - struct ival { - unsigned m_var; - const mpq & m_coeff; - ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) { - } - unsigned var() const { return m_var;} - const mpq & coeff() const { return m_coeff; } - }; - - term_with_basis_col(const C& row, unsigned bj) : m_row(row), m_bj(bj) {} - struct const_iterator { - // fields - typename C::const_iterator m_it; - unsigned m_bj; - - - //typedefs - - - typedef const_iterator self_type; - typedef ival value_type; - typedef ival reference; - typedef int difference_type; - typedef std::forward_iterator_tag iterator_category; - - reference operator*() const { - if (m_bj == static_cast(-1)) - return ival((*m_it).var(), (*m_it).coeff()); - return ival(m_bj, - 1); - } - self_type operator++() { self_type i = *this; operator++(1); return i; } - - self_type operator++(int) { - if (m_bj == static_cast(-1)) - m_it++; - else - m_bj = static_cast(-1); - return *this; - } - - // constructor - const_iterator(const typename C::const_iterator& it, unsigned bj) : - m_it(it), - m_bj(bj) - {} - bool operator==(const self_type &other) const { - return m_it == other.m_it && m_bj == other.m_bj ; - } - bool operator!=(const self_type &other) const { return !(*this == other); } - }; - const_iterator begin() const { - return const_iterator( m_row.begin(), m_bj); - } - const_iterator end() const { return const_iterator(m_row.end(), m_bj); } - }; - term_with_basis_col m_row; + const C& m_row; bound_propagator & m_bp; unsigned m_row_or_term_index; int m_column_of_u; // index of an unlimited from above monoid @@ -105,7 +47,7 @@ public : bound_propagator & bp ) : - m_row(it, bj), + m_row(it), m_bp(bp), m_row_or_term_index(row_or_term_index), m_column_of_u(-1), @@ -117,6 +59,8 @@ public : unsigned j; void analyze() { for (const auto & c : m_row) { + if (c.dead()) + continue; if ((m_column_of_l == -2) && (m_column_of_u == -2)) break; analyze_bound_on_var_on_coeff(c.var(), c.coeff()); @@ -226,6 +170,7 @@ public : mpq total; lp_assert(is_zero(total)); for (const auto& p : m_row) { + if (p.dead()) continue; bool str; total -= monoid_min(p.coeff(), p.var(), str); if (str) @@ -234,6 +179,7 @@ public : for (const auto &p : m_row) { + if (p.dead()) continue; bool str; bool a_is_pos = is_pos(p.coeff()); mpq bound = total / p.coeff() + monoid_min_no_mult(a_is_pos, p.var(), str); @@ -251,6 +197,7 @@ public : mpq total; lp_assert(is_zero(total)); for (const auto &p : m_row) { + if (p.dead()) continue; bool str; total -= monoid_max(p.coeff(), p.var(), str); if (str) @@ -258,6 +205,7 @@ public : } for (const auto& p : m_row) { + if (p.dead()) continue; bool str; bool a_is_pos = is_pos(p.coeff()); mpq bound = total / p.coeff() + monoid_max_no_mult(a_is_pos, p.var(), str); @@ -280,6 +228,7 @@ public : mpq bound = -m_rs.x; bool strict = false; for (const auto& p : m_row) { + if (p.dead()) continue; j = p.var(); if (j == static_cast(m_column_of_u)) { u_coeff = p.coeff(); @@ -309,6 +258,7 @@ public : mpq bound = -m_rs.x; bool strict = false; for (const auto &p : m_row) { + if (p.dead()) continue; j = p.var(); if (j == static_cast(m_column_of_l)) { l_coeff = p.coeff(); diff --git a/src/util/lp/bound_propagator.cpp b/src/util/lp/bound_propagator.cpp index c4fa2aefa..199fef9b0 100644 --- a/src/util/lp/bound_propagator.cpp +++ b/src/util/lp/bound_propagator.cpp @@ -16,6 +16,8 @@ const impq & bound_propagator::get_upper_bound(unsigned j) const { return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j]; } void bound_propagator::try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) { + TRACE("try_add_bound", + tout << "v = " << v << ", j = " << j << std::endl;); j = m_lar_solver.adjust_column_index_to_term_index(j); if (m_lar_solver.is_term(j)) { // lp treats terms as not having a free coefficient, restoring it below for the outside consumption diff --git a/src/util/lp/core_solver_pretty_printer_def.h b/src/util/lp/core_solver_pretty_printer_def.h index 58ffbb481..dcf3e0a11 100644 --- a/src/util/lp/core_solver_pretty_printer_def.h +++ b/src/util/lp/core_solver_pretty_printer_def.h @@ -100,7 +100,7 @@ template void core_solver_pretty_printer::init_m_ for (unsigned column = 0; column < ncols(); column++) { vector t(nrows(), zero_of_type()); for (const auto & c : m_core_solver.m_A.m_columns[column]){ - t[c.m_i] = m_core_solver.m_A.get_val(c); + t[c.var()] = m_core_solver.m_A.get_val(c); } string name = m_core_solver.column_name(column); diff --git a/src/util/lp/indexed_vector.h b/src/util/lp/indexed_vector.h index d472a4a1e..24078ce84 100644 --- a/src/util/lp/indexed_vector.h +++ b/src/util/lp/indexed_vector.h @@ -172,6 +172,7 @@ public: } unsigned var() const { return m_var;} const T & coeff() const { return m_coeff; } + bool dead() const { return false; } }; struct const_iterator { diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 2e744e3d6..78206dc53 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -100,6 +100,7 @@ bool int_solver::is_gomory_cut_target(const row_strip& row) { // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). unsigned j; for (const auto & p : row) { + if (p.dead()) continue; j = p.var(); if (is_base(j)) continue; if (!at_bound(j)) @@ -311,6 +312,7 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row TRACE("gomory_cut", tout << "applying cut at:\n"; m_lar_solver->print_row(row, tout); tout << std::endl; for (auto & p : row) { + if (p.dead()) continue; m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(p.var(), tout); } tout << "inf_col = " << inf_col << std::endl; @@ -324,7 +326,8 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row bool some_int_columns = false; mpq f_0 = int_solver::fractional_part(get_value(inf_col)); mpq one_min_f_0 = 1 - f_0; - for (auto & p : row) { + for (const auto & p : row) { + if (p.dead()) continue; x_j = p.var(); if (x_j == inf_col) continue; @@ -353,6 +356,7 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row int int_solver::find_free_var_in_gomory_row(const row_strip& row) { unsigned j; for (const auto & p : row) { + if (p.dead()) continue; j = p.var(); if (!is_base(j) && is_free(j)) return static_cast(j); @@ -789,6 +793,7 @@ lia_move int_solver::patch_nbasic_columns() { mpq get_denominators_lcm(const row_strip & row) { mpq r(1); for (auto & c : row) { + if (c.dead()) continue; r = lcm(r, denominator(c.coeff())); } return r; @@ -802,6 +807,7 @@ bool int_solver::gcd_test_for_row(static_matrix> & A, uns bool least_coeff_is_bounded = false; unsigned j; for (auto &c : A.m_rows[i]) { + if (c.dead()) continue; j = c.var(); const mpq& a = c.coeff(); if (m_lar_solver->column_is_fixed(j)) { @@ -867,6 +873,7 @@ void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j) { } void int_solver::fill_explanation_from_fixed_columns(const row_strip & row) { for (const auto & c : row) { + if (c.dead()) continue; if (!m_lar_solver->column_is_fixed(c.var())) continue; add_to_explanation_from_fixed_or_boxed_column(c.var()); @@ -892,6 +899,7 @@ bool int_solver::ext_gcd_test(const row_strip & row, mpq a; unsigned j; for (const auto & c : row) { + if (c.dead()) continue; j = c.var(); const mpq & a = c.coeff(); if (m_lar_solver->column_is_fixed(j)) @@ -1023,6 +1031,7 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq lp_assert(settings().use_tableau()); const auto & A = m_lar_solver->A_r(); for (const auto &c : A.column(j)) { + if (c.dead()) continue; row_index = c.var(); const mpq & a = c.coeff(); @@ -1152,13 +1161,15 @@ bool int_solver::at_upper(unsigned j) const { void int_solver::display_row_info(std::ostream & out, unsigned row_index) const { auto & rslv = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; - for (auto &c: rslv.m_A.m_rows[row_index]) { + for (const auto &c: rslv.m_A.m_rows[row_index]) { + if (c.dead()) continue; if (numeric_traits::is_pos(c.coeff())) out << "+"; out << c.coeff() << rslv.column_name(c.var()) << " "; } - for (auto& c: rslv.m_A.m_rows[row_index]) { + for (const auto& c: rslv.m_A.m_rows[row_index]) { + if (c.dead()) continue; rslv.print_column_bound_info(c.var(), out); } rslv.print_column_bound_info(rslv.m_basis[row_index], out); diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 5f5518528..4223f5964 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -339,7 +339,7 @@ public: if (!update_xj_and_get_delta(j, pos_type, delta)) continue; for (const auto & cc : m_r_solver.m_A.m_columns[j]){ - unsigned i = cc.m_i; + unsigned i = cc.var(); unsigned jb = m_r_solver.m_basis[i]; m_r_solver.update_x_with_delta_and_track_feasibility(jb, - delta * m_r_solver.m_A.get_val(cc)); } @@ -583,8 +583,7 @@ public: if (!m_r_solver.m_settings.use_tableau()) return true; for (unsigned j : m_r_solver.m_basis) { - lp_assert(m_r_solver.m_A.m_columns[j].size() == 1); - lp_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type()); + lp_assert(m_r_solver.m_A.m_columns[j].live_size() == 1); } for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) { if (m_r_solver.m_basis_heading[j] >= 0) continue; @@ -633,8 +632,9 @@ public: void create_double_matrix(static_matrix & A) { for (unsigned i = 0; i < m_r_A.row_count(); i++) { auto & row = m_r_A.m_rows[i]; - for (row_cell & c : row) { - A.set(i, c.m_j, c.get_val().get_double()); + for (row_cell & c : row.m_cells) { + if (c.dead()) continue; + A.add_new_element(i, c.var(), c.get_val().get_double()); } } } diff --git a/src/util/lp/lar_core_solver_def.h b/src/util/lp/lar_core_solver_def.h index f9937e77a..c626362fc 100644 --- a/src/util/lp/lar_core_solver_def.h +++ b/src/util/lp/lar_core_solver_def.h @@ -226,8 +226,9 @@ void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); m_infeasible_linear_combination.clear(); - for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau]) { - m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.m_j)); + for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau].m_cells) { + if (rc.dead()) continue; + m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.var())); } } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index c4f7ff196..5408bd922 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -162,9 +162,8 @@ void lar_solver::analyze_new_bounds_on_row_tableau( unsigned row_index, bound_propagator & bp ) { - if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation) + if (A_r().m_rows[row_index].live_size() > settings().max_row_length_for_bound_propagation) return; - lp_assert(use_tableau()); bound_analyzer_on_row>::analyze_row(A_r().m_rows[row_index], static_cast(-1), @@ -216,7 +215,8 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp bound_j = m_var_register.external_to_local(bound_j); } for (auto const& r : A_r().m_rows[i]) { - unsigned j = r.m_j; + if (r.dead()) continue; + unsigned j = r.var(); if (j == bound_j) continue; mpq const& a = r.get_val(); int a_sign = is_pos(a)? 1: -1; @@ -428,8 +428,9 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { if (i < 0) jset.insert(j); else { - for (auto & rc : A_r().m_rows[i]) - jset.insert(rc.m_j); + for (const auto & rc : A_r().m_rows[i]) + if (rc.alive()) + jset.insert(rc.var()); } } @@ -639,7 +640,8 @@ void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { for (auto & rc : m_mpq_lar_core_solver.m_r_A.m_columns[j]) - m_rows_with_changed_bounds.insert(rc.m_i); + if (rc.alive()) + m_rows_with_changed_bounds.insert(rc.var()); } bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } @@ -667,8 +669,10 @@ void lar_solver::adjust_x_of_column(unsigned j) { bool lar_solver::row_is_correct(unsigned i) const { numeric_pair r = zero_of_type>(); - for (const auto & c : A_r().m_rows[i]) - r += c.m_value * m_mpq_lar_core_solver.m_r_x[c.m_j]; + for (const auto & c : A_r().m_rows[i]) { + if (c.dead()) continue; + r += c.coeff() * m_mpq_lar_core_solver.m_r_x[c.var()]; + } return is_zero(r); } @@ -691,7 +695,8 @@ bool lar_solver::costs_are_used() const { void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta) { if (use_tableau()) { for (const auto & c : A_r().m_columns[j]) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.m_i]; + if (c.dead()) continue; + unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; if (tableau_with_costs()) { m_basic_columns_with_changed_cost.insert(bj); } @@ -790,10 +795,10 @@ numeric_pair lar_solver::get_basic_var_value_from_row_directly(unsigned i) unsigned bj = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; for (const auto & c: A_r().m_rows[i]) { - if (c.m_j == bj) continue; - const auto & x = m_mpq_lar_core_solver.m_r_x[c.m_j]; + if (c.var() == bj) continue; + const auto & x = m_mpq_lar_core_solver.m_r_x[c.var()]; if (!is_zero(x)) - r -= c.m_value * x; + r -= c.coeff() * x; } return r; } @@ -866,14 +871,14 @@ void lar_solver::fill_last_row_of_A_r(static_matrix> & A, lp_assert(A.row_count() > 0); lp_assert(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lp_assert(A.m_rows[last_row].size() == 0); + lp_assert(A.m_rows[last_row].live_size() == 0); for (auto & t : ls->m_coeffs) { lp_assert(!is_zero(t.second)); var_index j = t.first; - A.set(last_row, j, - t.second); + A.add_new_element(last_row, j, - t.second); } unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); + A.add_new_element(last_row, basis_j, mpq(1)); } template @@ -895,7 +900,7 @@ void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { matr.m_columns.resize(A_r().column_count()); for (unsigned i = 0; i < matr.row_count(); i++) { for (auto & it : A_r().m_rows[i]) { - matr.set(i, it.m_j, convert_struct::convert(it.get_val())); + matr.add_new_element(i, it.var(), convert_struct::convert(it.get_val())); } } } @@ -1327,16 +1332,17 @@ void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsign lp_assert(A_r().row_count() == i + 1 && A_r().column_count() == j + 1); auto & last_column = A_r().m_columns[j]; int non_zero_column_cell_index = -1; - for (unsigned k = last_column.size(); k-- > 0;){ + for (unsigned k = last_column.cells_size(); k-- > 0;){ auto & cc = last_column[k]; - if (cc.m_i == i) + if (cc.dead()) continue; + if (cc.var() == i) return; non_zero_column_cell_index = k; } lp_assert(non_zero_column_cell_index != -1); lp_assert(static_cast(non_zero_column_cell_index) != i); - m_mpq_lar_core_solver.m_r_solver.transpose_rows_tableau(last_column[non_zero_column_cell_index].m_i, i); + m_mpq_lar_core_solver.m_r_solver.transpose_rows_tableau(last_column[non_zero_column_cell_index].var(), i); } void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { @@ -1351,24 +1357,29 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { auto & last_row = A_r().m_rows[i]; mpq &cost_j = m_mpq_lar_core_solver.m_r_solver.m_costs[j]; bool cost_is_nz = !is_zero(cost_j); - for (unsigned k = last_row.size(); k-- > 0;) { + for (unsigned k = last_row.cells_size(); k-- > 0;) { auto &rc = last_row[k]; + if (rc.dead()) { + last_row.pop(); + continue; + } if (cost_is_nz) { - m_mpq_lar_core_solver.m_r_solver.m_d[rc.m_j] += cost_j*rc.get_val(); + m_mpq_lar_core_solver.m_r_solver.m_d[rc.var()] += cost_j*rc.get_val(); } - A_r().remove_element(last_row, rc); + A_r().remove_element(rc); } - lp_assert(last_row.size() == 0); - lp_assert(A_r().m_columns[j].size() == 0); + lp_assert(last_row.live_size() == 0); + lp_assert(A_r().m_columns[j].live_size() == 0); A_r().m_rows.pop_back(); A_r().m_columns.pop_back(); + lp_assert(A_r().is_correct()); slv.m_b.pop_back(); } void lar_solver::remove_last_column_from_A() { // the last column has to be empty - lp_assert(A_r().m_columns.back().size() == 0); + lp_assert(A_r().m_columns.back().live_size() == 0); A_r().m_columns.pop_back(); } @@ -1840,11 +1851,12 @@ void lar_solver::fill_last_row_of_A_d(static_matrix & A, const l for (auto & t : ls->m_coeffs) { lp_assert(!is_zero(t.second)); var_index j = t.first; - A.set(last_row, j, -t.second.get_double()); + A.add_new_element(last_row, j, -t.second.get_double()); } unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, -1); + A.add_new_element(last_row, basis_j, -1); + lp_assert(A.is_correct()); } void lar_solver::update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) { diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index b8b7b7c0d..35a989c07 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -213,8 +213,17 @@ public: unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; - lp_assert(m_A.m_columns[bj].size() > 0); - if (m_A.m_columns[bj].size() > 1 || m_A.get_val(m_A.m_columns[bj][0]) != one_of_type()) return true; + lp_assert(m_A.m_columns[bj].live_size() > 0); + if (m_A.m_columns[bj].live_size() > 1) + return true; + for (const auto & c : m_A.m_columns[bj]) { + if (c.dead()) + continue; + if (m_A.get_val(c) != one_of_type()) + return true; + else + break; + } } return false; } @@ -237,8 +246,9 @@ public: } } else { auto d = m_costs[j]; - for (auto & cc : this->m_A.m_columns[j]) { - d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc); + for (const auto & cc : this->m_A.m_columns[j]) { + if (cc.dead()) continue; + d -= this->m_costs[this->m_basis[cc.var()]] * this->m_A.get_val(cc); } if (m_d[j] != d) { return false; diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index f20eaf042..ddae7bf20 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -103,9 +103,12 @@ pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { T &a = m_d[j]; if (is_zero(a)) return; - for (const row_cell & r: m_A.m_rows[i]) - if (r.m_j != j) - m_d[r.m_j] -= a * r.get_val(); + for (const row_cell & r: m_A.m_rows[i]){ + if (r.dead()) continue; + if (r.var() != j) + m_d[r.var()] -= a * r.get_val(); + } +ls a = zero_of_type(); // zero the pivot column's m_d finally } @@ -308,8 +311,9 @@ calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row) { if (numeric_traits::is_zero(pi_1)) { continue; } - for (auto & c : m_A.m_rows[i]) { - unsigned j = c.m_j; + for (auto & c : m_A.m_rows[i].m_cells) { + if (c.dead()) continue; + unsigned j = c.var(); if (m_basis_heading[j] < 0) { m_pivot_row.add_value_at_index_with_drop_tolerance(j, c.get_val() * pi_1); } @@ -331,7 +335,7 @@ update_x(unsigned entering, const X& delta) { } else for (const auto & c : m_A.m_columns[entering]) { - unsigned i = c.m_i; + unsigned i = c.var(); m_x[m_basis[i]] -= delta * m_A.get_val(c); } } @@ -449,7 +453,7 @@ rs_minus_Anx(vector & rs) { while (row--) { auto &rsv = rs[row] = m_b[row]; for (auto & it : m_A.m_rows[row]) { - unsigned j = it.m_j; + unsigned j = it.var(); if (m_basis_heading[j] < 0) { rsv -= m_x[j] * it.get_val(); } @@ -589,9 +593,11 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { lp_assert(numeric_traits::precise()); int pivot_index = -1; auto & row = m_A.m_rows[pivot_row]; - unsigned size = row.size(); + unsigned size = row.cells_size(); for (unsigned j = 0; j < size; j++) { - if (row[j].m_j == pivot_col) { + auto & c = row[j]; + if (c.dead()) continue; + if (c.var() == pivot_col) { pivot_index = static_cast(j); break; } @@ -599,26 +605,33 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { if (pivot_index == -1) return false; auto & pivot_cell = row[pivot_index]; - if (is_zero(pivot_cell.m_value)) + T & coeff = pivot_cell.coeff(); + if (is_zero(coeff)) return false; - this->m_b[pivot_row] /= pivot_cell.m_value; + this->m_b[pivot_row] /= coeff; for (unsigned j = 0; j < size; j++) { - if (row[j].m_j != pivot_col) { - row[j].m_value /= pivot_cell.m_value; + auto & c = row[j]; + if (c.dead()) continue; + if (c.var() != pivot_col) { + c.coeff() /= coeff; } } - pivot_cell.m_value = one_of_type(); + coeff = one_of_type(); + lp_assert(m_A.is_correct()); return true; } template bool lp_core_solver_base:: pivot_column_tableau(unsigned j, unsigned piv_row_index) { - if (!divide_row_by_pivot(piv_row_index, j)) + lp_assert(m_A.is_correct()); + m_A.compress_row_if_needed(piv_row_index); + if (!divide_row_by_pivot(piv_row_index, j)) return false; auto &column = m_A.m_columns[j]; int pivot_col_cell_index = -1; - for (unsigned k = 0; k < column.size(); k++) { - if (column[k].m_i == piv_row_index) { + for (unsigned k = 0; k < column.cells_size(); k++) { + if (column[k].dead()) continue; + if (column[k].var() == piv_row_index) { pivot_col_cell_index = k; break; } @@ -626,25 +639,26 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { if (pivot_col_cell_index < 0) return false; - if (pivot_col_cell_index != 0) { - lp_assert(column.size() > 1); - // swap the pivot column cell with the head cell - auto c = column[0]; - column[0] = column[pivot_col_cell_index]; - column[pivot_col_cell_index] = c; + if (pivot_col_cell_index != 0) + m_A.swap_with_head_cell(j, pivot_col_cell_index); - m_A.m_rows[piv_row_index][column[0].m_offset].m_offset = 0; - m_A.m_rows[c.m_i][c.m_offset].m_offset = pivot_col_cell_index; - } - while (column.size() > 1) { + lp_assert(m_A.is_correct()); + while (column.live_size() > 1) { auto & c = column.back(); - lp_assert(c.m_i != piv_row_index); + if (c.dead()) { + column.pop_last_dead_cell(); + continue; + } + lp_assert(c.var() != piv_row_index); if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) { return false; } if (m_pivoted_rows!= nullptr) - m_pivoted_rows->insert(c.m_i); + m_pivoted_rows->insert(c.var()); } + m_A.compress_column_if_needed(j); + lp_assert(column.live_size() == 1); + lp_assert(m_A.is_correct()); if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs) pivot_to_reduced_costs_tableau(piv_row_index, j); @@ -758,10 +772,11 @@ fill_reduced_costs_from_m_y_by_rows() { while (i--) { const T & y = m_y[i]; if (is_zero(y)) continue; - for (row_cell & it : m_A.m_rows[i]) { - j = it.m_j; + for (row_cell & c : m_A.m_rows[i].m_cells) { + if (c.dead()) continue; + j = c.var(); if (m_basis_heading[j] < 0) { - m_d[j] -= y * it.get_val(); + m_d[j] -= y * c.get_val(); } } } @@ -802,7 +817,7 @@ find_error_in_BxB(vector& rs){ while (row--) { auto &rsv = rs[row]; for (auto & it : m_A.m_rows[row]) { - unsigned j = it.m_j; + unsigned j = it.var(); if (m_basis_heading[j] >= 0) { rsv -= m_x[j] * it.get_val(); } @@ -957,7 +972,8 @@ template void lp_core_solver_base::pivot_fixed_v if (get_column_type(basic_j) != column_type::fixed) continue; T a; unsigned j; - for (auto &c : m_A.m_rows[i]) { + for (auto &c : m_A.m_rows[i].m_cells) { + if (c.dead()) continue; j = c.var(); if (j == basic_j) continue; @@ -972,7 +988,8 @@ template void lp_core_solver_base::pivot_fixed_v template bool lp_core_solver_base::remove_from_basis(unsigned basic_j) { indexed_vector w(m_basis.size()); // the buffer unsigned i = m_basis_heading[basic_j]; - for (auto &c : m_A.m_rows[i]) { + for (auto &c : m_A.m_rows[i].m_cells) { + if (c.dead()) continue; if (c.var() == basic_j) continue; if (pivot_column_general(c.var(), basic_j, w)) @@ -1043,8 +1060,8 @@ void lp_core_solver_base::calculate_pivot_row(unsigned i) { if (m_settings.use_tableau()) { unsigned basic_j = m_basis[i]; for (auto & c : m_A.m_rows[i]) { - if (c.m_j != basic_j) - m_pivot_row.set_value(c.get_val(), c.m_j); + if (c.var() != basic_j) + m_pivot_row.set_value(c.get_val(), c.var()); } return; } diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index 26fc550b3..2700fc168 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -172,7 +172,7 @@ public: bool monoid_can_decrease(const row_cell & rc) const { - unsigned j = rc.m_j; + unsigned j = rc.var(); lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: @@ -205,7 +205,7 @@ public: } bool monoid_can_increase(const row_cell & rc) const { - unsigned j = rc.m_j; + unsigned j = rc.var(); lp_assert(this->column_is_feasible(j)); switch (this->m_column_types[j]) { case column_type::free_column: @@ -239,8 +239,9 @@ public: unsigned get_number_of_basic_vars_that_might_become_inf(unsigned j) const { // consider looking at the signs here: todo unsigned r = 0; - for (auto & cc : this->m_A.m_columns[j]) { - unsigned k = this->m_basis[cc.m_i]; + for (const auto & cc : this->m_A.m_columns[j]) { + if (cc.dead()) continue; + unsigned k = this->m_basis[cc.var()]; if (this->m_column_types[k] != column_type::free_column) r++; } @@ -253,7 +254,8 @@ public: unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); for (const row_cell& rc : this->m_A.m_rows[i]) { - if (rc.m_j == bj) + if (rc.dead()) continue; + if (rc.var() == bj) continue; if (bj_needs_to_grow) { if (!monoid_can_decrease(rc)) @@ -262,9 +264,9 @@ public: if (!monoid_can_increase(rc)) continue; } - if (rc.m_j < static_cast(j) ) { - j = rc.m_j; - a_ent = rc.m_value; + if (rc.var() < static_cast(j) ) { + j = rc.var(); + a_ent = rc.coeff(); } } if (j == -1) { @@ -278,13 +280,18 @@ public: if (m_bland_mode_tableau) return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); // a short row produces short infeasibility explanation and benefits at least one pivot operation - vector*> choices; - unsigned num_of_non_free_basics = 1000000; + int choice = -1; + int nchoices = 0; unsigned len = 100000000; unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); - for (const row_cell& rc : this->m_A.m_rows[i]) { - unsigned j = rc.m_j; + for (unsigned k = 0; k < this->m_A.m_rows[i].m_cells.size(); k++) { + const row_cell& rc = this->m_A.m_rows[i].m_cells[k]; + if (rc.dead()) continue; + const row_cell& rc = this->m_A.m_rows[i].m_cells[k]; + if (rc.dead()) continue; +>>>>>>> e6c612f... trying the new scheme in static_matrix : in progress + unsigned j = rc.var(); if (j == bj) continue; if (bj_needs_to_grow) { @@ -297,26 +304,24 @@ public: unsigned damage = get_number_of_basic_vars_that_might_become_inf(j); if (damage < num_of_non_free_basics) { num_of_non_free_basics = damage; - len = this->m_A.m_columns[j].size(); - choices.clear(); - choices.push_back(&rc); + len = this->m_A.m_columns[j].live_size(); + choice = k; + nchoices = 1; } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % 2)) { - choices.push_back(&rc); - len = this->m_A.m_columns[j].size(); + this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % (++nchoices))) { + choice = k; + len = this->m_A.m_columns[j].live_size(); } } - if (choices.size() == 0) { + if (choice == -1) { m_inf_row_index_for_tableau = i; return -1; } - const row_cell* rc = choices.size() == 1? choices[0] : - choices[this->m_settings.random_next() % choices.size()]; - - a_ent = rc->m_value; - return rc->m_j; + const row_cell& rc = this->m_A.m_rows[i].m_cells[choice]; + a_ent = rc.coeff(); + return rc.var(); } static X positive_infinity() { return convert_struct::convert(std::numeric_limits::max()); @@ -827,11 +832,11 @@ public: this->m_rows_nz.resize(this->m_A.row_count()); for (unsigned i = 0; i < this->m_A.column_count(); i++) { if (this->m_columns_nz[i] == 0) - this->m_columns_nz[i] = this->m_A.m_columns[i].size(); + this->m_columns_nz[i] = this->m_A.m_columns[i].live_size(); } for (unsigned i = 0; i < this->m_A.row_count(); i++) { if (this->m_rows_nz[i] == 0) - this->m_rows_nz[i] = this->m_A.m_rows[i].size(); + this->m_rows_nz[i] = this->m_A.m_rows[i].live_size(); } } @@ -861,7 +866,7 @@ public: unsigned solve_with_tableau(); bool basis_column_is_set_correctly(unsigned j) const { - return this->m_A.m_columns[j].size() == 1; + return this->m_A.m_columns[j].live_size() == 1; } @@ -881,7 +886,8 @@ public: lp_assert(this->m_basis_heading[j] >= 0); unsigned i = static_cast(this->m_basis_heading[j]); for (const row_cell & rc : this->m_A.m_rows[i]) { - unsigned k = rc.m_j; + if (rc.dead()) continue; + unsigned k = rc.var(); if (k == j) continue; this->m_d[k] += delta * rc.get_val(); diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index 1e9edbd31..eb4a9ce1d 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -975,7 +975,7 @@ template void lp_primal_core_solver::delete_fa template void lp_primal_core_solver::init_column_norms() { lp_assert(numeric_traits::precise() == false); for (unsigned j = 0; j < this->m_n(); j++) { - this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].size() + 1)) + this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].live_size() + 1)) + T(static_cast(this->m_settings.random_next() % 10000)) / T(100000); } diff --git a/src/util/lp/lp_primal_core_solver_tableau_def.h b/src/util/lp/lp_primal_core_solver_tableau_def.h index f85c131a3..be28bf36f 100644 --- a/src/util/lp/lp_primal_core_solver_tableau_def.h +++ b/src/util/lp/lp_primal_core_solver_tableau_def.h @@ -266,17 +266,18 @@ template int lp_primal_core_solver::find_leaving_ unsigned row_min_nz = this->m_n() + 1; m_leaving_candidates.clear(); auto & col = this->m_A.m_columns[entering]; - unsigned col_size = col.size(); + unsigned col_size = col.cells_size(); for (;k < col_size && unlimited; k++) { const column_cell & c = col[k]; - unsigned i = c.m_i; + if (c.dead()) continue; + unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); if (!unlimited) { m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].size(); + row_min_nz = this->m_A.m_rows[i].live_size(); } } if (unlimited) { @@ -288,14 +289,15 @@ template int lp_primal_core_solver::find_leaving_ X ratio; for (;k < col_size; k++) { const column_cell & c = col[k]; - unsigned i = c.m_i; + if (c.dead()) continue; + unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); unsigned j = this->m_basis[i]; unlimited = true; limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); if (unlimited) continue; - unsigned i_nz = this->m_A.m_rows[i].size(); + unsigned i_nz = this->m_A.m_rows[i].live_size(); if (ratio < t) { t = ratio; m_leaving_candidates.clear(); @@ -304,7 +306,7 @@ template int lp_primal_core_solver::find_leaving_ } else if (ratio == t && i_nz < row_min_nz) { m_leaving_candidates.clear(); m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].size(); + row_min_nz = this->m_A.m_rows[i].live_size(); } else if (ratio == t && i_nz == row_min_nz) { m_leaving_candidates.push_back(j); } @@ -348,6 +350,7 @@ template void lp_primal_core_solver::init_run_tab template bool lp_primal_core_solver:: update_basis_and_x_tableau(int entering, int leaving, X const & tt) { lp_assert(this->use_tableau()); + lp_assert(entering != leaving); update_x_tableau(entering, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); this->change_basis(entering, leaving); @@ -358,7 +361,8 @@ update_x_tableau(unsigned entering, const X& delta) { this->add_delta_to_x_and_call_tracker(entering, delta); if (!this->m_using_infeas_costs) { for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; + if (c.dead()) continue; + unsigned i = c.var(); this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c)); } } else { // m_using_infeas_costs == true @@ -366,7 +370,7 @@ update_x_tableau(unsigned entering, const X& delta) { lp_assert(this->m_costs[entering] == zero_of_type()); // m_d[entering] can change because of the cost change for basic columns. for (const auto & c : this->m_A.m_columns[entering]) { - unsigned i = c.m_i; + unsigned i = c.var(); unsigned j = this->m_basis[i]; this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c)); update_inf_cost_for_column_tableau(j); @@ -407,7 +411,7 @@ template void lp_primal_core_solver::init_reduced else { T& d = this->m_d[j] = this->m_costs[j]; for (auto & cc : this->m_A.m_columns[j]) { - d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc); + d -= this->m_costs[this->m_basis[cc.var()]] * this->m_A.get_val(cc); } } } diff --git a/src/util/lp/lu.h b/src/util/lp/lu.h index 3b5a9cc59..95c00414e 100644 --- a/src/util/lp/lu.h +++ b/src/util/lp/lu.h @@ -330,11 +330,11 @@ public: for (unsigned i = m_prev; i < m; i++) { for (const row_cell & c : m_A.m_rows[i]) { - int h = heading[c.m_j]; + int h = heading[c.var()]; if (h < 0) { continue; } - columns_to_replace.insert(c.m_j); + columns_to_replace.insert(c.var()); } } return columns_to_replace; diff --git a/src/util/lp/lu_def.h b/src/util/lp/lu_def.h index 51f291e7e..00d0466b7 100644 --- a/src/util/lp/lu_def.h +++ b/src/util/lp/lu_def.h @@ -386,7 +386,7 @@ void lu< M>::find_error_of_yB_indexed(const indexed_vector& y, const vector::add_columns_at_the_end(unsigned int); +template void static_matrix::add_new_element(unsigned i, unsigned j, const double & v); +template void static_matrix::add_new_element(unsigned i, unsigned j, const mpq & v); +template void static_matrix::add_new_element(unsigned i, unsigned j, const mpq & v); template void static_matrix::clear(); #ifdef Z3DEBUG template bool static_matrix::is_correct() const; @@ -47,7 +50,6 @@ template double static_matrix::get_min_abs_in_row(unsigned int) template void static_matrix::init_empty_matrix(unsigned int, unsigned int); template void static_matrix::init_row_columns(unsigned int, unsigned int); template static_matrix::ref & static_matrix::ref::operator=(double const&); -template void static_matrix::set(unsigned int, unsigned int, double const&); template static_matrix::static_matrix(unsigned int, unsigned int); template void static_matrix::add_column_to_vector(mpq const&, unsigned int, mpq*) const; template void static_matrix::add_columns_at_the_end(unsigned int); @@ -63,7 +65,6 @@ template mpq static_matrix::get_min_abs_in_column(unsigned int) const; template mpq static_matrix::get_min_abs_in_row(unsigned int) const; template void static_matrix::init_row_columns(unsigned int, unsigned int); template static_matrix::ref& static_matrix::ref::operator=(mpq const&); -template void static_matrix::set(unsigned int, unsigned int, mpq const&); template static_matrix::static_matrix(unsigned int, unsigned int); #ifdef Z3DEBUG @@ -72,13 +73,11 @@ template bool static_matrix >::is_correct() const; template void static_matrix >::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; template mpq static_matrix >::get_elem(unsigned int, unsigned int) const; template void static_matrix >::init_empty_matrix(unsigned int, unsigned int); -template void static_matrix >::set(unsigned int, unsigned int, mpq const&); - template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); template bool lp::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); -template void lp::static_matrix >::remove_element(vector, true, unsigned int>&, lp::row_cell&); +template void lp::static_matrix >::remove_element(lp::row_cell&); } diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index e4bf257f4..036f628b7 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -1,22 +1,22 @@ /*++ -Copyright (c) 2017 Microsoft Corporation + Copyright (c) 2017 Microsoft Corporation -Module Name: + Module Name: - + -Abstract: + Abstract: - + -Author: + Author: - Lev Nachmanson (levnach) + Lev Nachmanson (levnach) -Revision History: + Revision History: ---*/ + --*/ #pragma once #include "util/vector.h" @@ -29,30 +29,387 @@ Revision History: #include namespace lp { -struct column_cell { - unsigned m_i; // points to the row - unsigned m_offset; // the offset of the element in the matrix row - column_cell(unsigned i, unsigned offset) : m_i(i), m_offset(offset) { +class column_cell { + unsigned m_i; // points to the row + unsigned m_offset; // the offset of the element in the matrix row, or the next dead cell in the column_strip +public: + column_cell(unsigned i, unsigned offset) : m_i(i), m_offset(offset) { } + column_cell(unsigned i) : m_i(i) { } + + // index of of the cell row + unsigned var() const { + lp_assert(alive()); + return m_i; + } + unsigned &var() { + return m_i; + } + unsigned offset() const { + lp_assert(alive()); + return m_offset; + } + unsigned & offset() { + lp_assert(alive()); + return m_offset; + } + + unsigned next_dead_index() const { + lp_assert(dead()); + return m_offset; + } + unsigned & next_dead_index() { + return m_offset; } + bool alive() const { return !dead(); } + bool dead() const { return m_i == static_cast(-1); } + void set_dead() { m_i = -1;} + + + }; template -struct row_cell { - unsigned m_j; // points to the column - unsigned m_offset; // offset in column - T m_value; +class row_cell { + unsigned m_j; // points to the column + unsigned m_offset; // offset in column, or the next dead cell in the row_strip + T m_value; +public: row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_value(val) { } - const T & get_val() const { return m_value;} - T & get_val() { return m_value;} - void set_val(const T& v) { m_value = v; } - unsigned var() const { return m_j;} - const T & coeff() const { return m_value;} + row_cell(unsigned j, T const & val) : m_j(j), m_value(val) { + } + const T & get_val() const { + lp_assert(alive()); + return m_value; + } + T & get_val() { + lp_assert(alive()); + return m_value; + } + void set_val(const T& v) { + lp_assert(alive()); + m_value = v; + } + // index of the cell column + unsigned var() const { + lp_assert(alive()); + return m_j; + } + unsigned &var() { + return m_j; + } + const T & coeff() const { + lp_assert(alive()); + return m_value; + } + T & coeff() { + lp_assert(alive()); + return m_value; + } + // offset in the column vector + unsigned offset() const { + lp_assert(alive()); + return m_offset; + } + unsigned & offset() { + return m_offset; + } + unsigned next_dead_index() const { + lp_assert(dead()); + return m_offset; + } + unsigned & next_dead_index() { + lp_assert(dead()); + return m_offset; + } + bool alive() const { return !dead(); } + bool dead() const { return m_j == static_cast(-1); } + void set_dead() { m_j = static_cast(-1); } + + }; template -using row_strip = vector>; +class row_strip { + unsigned m_live_size; + int m_first_dead; +public: + row_strip() : m_live_size(0), m_first_dead(-1) {} + row_cell* begin() { return m_cells.begin();} + const row_cell* begin() const { return m_cells.begin();} + row_cell* end() { return m_cells.end();} + const row_cell* end() const { return m_cells.end();} + unsigned live_size() const { return m_live_size; } + vector> m_cells; + unsigned cells_size() const { return m_cells.size(); } + const row_cell & operator[](unsigned i) const { return m_cells[i]; } + row_cell & operator[](unsigned i) { return m_cells[i];} + + void skip_dead_cell(unsigned k) { + lp_assert(m_cells[k].dead()) + auto * c = &m_cells[m_first_dead]; + for (; c->next_dead_index() != k; c = &m_cells[c->next_dead_index()]); + lp_assert(c->next_dead_index() == k); + c->next_dead_index() = m_cells[k].next_dead_index(); + } + + void pop_last_dead_cell() { + lp_assert(m_cells.back().dead()); + unsigned last = m_cells.size() - 1; + if (m_first_dead == static_cast(last)) + m_first_dead = m_cells.back().next_dead_index(); + else { + skip_dead_cell(last); + } + m_cells.pop_back(); + } + + void pop(){ + bool dead = m_cells.back().dead(); + if (dead) { + pop_last_dead_cell(); + } else { + m_live_size --; + m_cells.pop_back(); + } + } + + bool empty() const { return m_live_size == 0; } + + void delete_at(unsigned j) { + lp_assert(m_cells[j].alive()); + m_live_size--; + if (j == m_cells.size() - 1) + m_cells.pop_back(); + else { + auto & c = m_cells[j]; + c.set_dead(); + c.next_dead_index() = m_first_dead; + m_first_dead = j; + } + lp_assert(is_correct()); + } + + bool is_correct() const { + std::set d0; + std::set d1; + unsigned alive = 0; + for (unsigned i = 0; i < m_cells.size(); i++) { + if (m_cells[i].dead()) + d0.insert(i); + else + alive ++; + } + + if ( alive != m_live_size) + return false; + + for (unsigned i = m_first_dead; i != static_cast(-1) ; i = m_cells[i].next_dead_index()) + d1.insert(i); + return d0 == d1; + } + + row_cell & add_cell(unsigned j, const T& val, unsigned & index) { +#ifdef Z3DEBUG + for (const auto & c : m_cells) { + if (c.dead()) continue; + if (c.var() == j) + std::cout << "oops" << std::endl; + } +#endif + if (m_first_dead != -1) { + auto & ret = m_cells[index = m_first_dead]; + m_first_dead = ret.next_dead_index(); + m_live_size++; + ret.var() = j; + ret.coeff() = val; + return ret; + } + lp_assert(m_live_size == m_cells.size()); + index = m_live_size++; + m_cells.push_back(row_cell(j, val)); + return m_cells.back(); + } + + void shrink_to_live() { + m_cells.shrink(live_size()); + m_first_dead = -1; + } +}; + +class column_strip { + vector m_cells; + unsigned m_live_size; + int m_first_dead; +public: + column_strip() : m_live_size(0), m_first_dead(-1) { } + column_cell* begin() { return m_cells.begin();} + const column_cell* begin() const { return m_cells.begin();} + column_cell* end() { return m_cells.end();} + const column_cell* end() const { return m_cells.end();} + unsigned live_size() const { + return m_live_size; + } + + unsigned cells_size() const { + return m_cells.size(); + } + + unsigned cells_size() const { + return m_cells.size(); + } + + column_cell& back() { return m_cells.back(); } + void delete_at(unsigned j) { + lp_assert(m_cells[j].alive()); + m_live_size--; + if (j == m_cells.size() - 1) + m_cells.pop_back(); + else { + auto & c = m_cells[j]; + c.set_dead(); + c.next_dead_index() = m_first_dead; + m_first_dead = j; + } + lp_assert(is_correct()); + } + + const column_cell& operator[] (unsigned i) const { return m_cells[i];} + column_cell& operator[](unsigned i) { return m_cells[i];} + void pop() { + bool dead = m_cells.back().dead(); + if (dead) { + pop_last_dead_cell(); + } else { + m_live_size --; + m_cells.pop_back(); + } + } + void skip_dead_cell(unsigned k) { + lp_assert(m_cells[k].dead()) + auto * c = &m_cells[m_first_dead]; + for (; c->next_dead_index() != k; c = &m_cells[c->next_dead_index()]); + lp_assert(c->next_dead_index() == k); + c->next_dead_index() = m_cells[k].next_dead_index(); + } + + void pop_last_dead_cell() { + lp_assert(m_cells.back().dead()); + unsigned last = m_cells.size() - 1; + if (m_first_dead == static_cast(last)) + m_first_dead = m_cells.back().next_dead_index(); + else { + skip_dead_cell(last); + } + m_cells.pop_back(); + } + + std::set d0; + std::set d1; + unsigned alive = 0; + for (unsigned i = 0; i < m_cells.size(); i++) { + if (m_cells[i].dead()) + d0.insert(i); + else + alive ++; + } + + if (alive != m_live_size) + return false; + for (unsigned i = m_first_dead; i != static_cast(-1) ; i = m_cells[i].next_dead_index()) + d1.insert(i); + return d0 == d1; + } + + void swap_with_head_cell(unsigned i) { + lp_assert(i > 0); + lp_assert(m_cells[i].alive()); + column_cell head_copy = m_cells[0]; + if (head_copy.dead()) { + if (m_first_dead == 0) { + m_first_dead = i; + } else { + column_cell * c = &m_cells[m_first_dead]; + for (; c->next_dead_index() != 0; c = &m_cells[c->next_dead_index()]); + lp_assert(c->next_dead_index() == 0); + c->next_dead_index() = i; + } + } + m_cells[0] = m_cells[i]; + m_cells[i] = head_copy; + lp_assert(is_correct()); + } + + void swap_with_head_cell(unsigned i) { + lp_assert(i > 0); + lp_assert(m_cells[i].alive()); + column_cell head_copy = m_cells[0]; + if (head_copy.dead()) { + if (m_first_dead == 0) { + m_first_dead = i; + } else { + column_cell * c = &m_cells[m_first_dead]; + for (; c->next_dead_index() != 0; c = &m_cells[c->next_dead_index()]); + lp_assert(c->next_dead_index() == 0); + c->next_dead_index() = i; + } + } + m_cells[0] = m_cells[i]; + m_cells[i] = head_copy; + lp_assert(is_correct()); + } + + column_cell & add_cell(unsigned i, unsigned & index) { + if (m_first_dead != -1) { + auto & ret = m_cells[index = m_first_dead]; + m_first_dead = ret.next_dead_index(); + m_live_size++; + ret.var() = i; + return ret; + } + lp_assert(m_live_size == m_cells.size()); + index = m_live_size++; + m_cells.push_back(column_cell(i)); + return m_cells.back(); + } + column_cell & add_cell(unsigned i, unsigned & index) { + if (m_first_dead != -1) { + auto & ret = m_cells[index = m_first_dead]; + m_first_dead = ret.next_dead_index(); + m_live_size++; + ret.var() = i; + return ret; + } + lp_assert(m_live_size == m_cells.size()); + index = m_live_size++; + m_cells.push_back(column_cell(i)); + return m_cells.back(); + } + void shrink_to_live() { + m_cells.shrink(live_size()); + m_first_dead = -1; + } +}; + +template +void compress_cells(A& cells, vector& vec_of_cells) { + if (2 * cells.live_size() < cells.cells_size()) + return; + unsigned j = 0; // the available target for copy + for (unsigned i = 0; i < cells.cells_size(); i++) { + auto & c = cells[i]; + if (c.dead()) continue; + if (i == j) { + j++; + continue; + } + vec_of_cells[c.var()][c.offset()].offset() = j; + cells[j++] = c; + } + cells.shrink_to_live(); +} + // each assignment for this matrix should be issued only once!!! template @@ -66,13 +423,13 @@ class static_matrix unsigned m_n; dim(unsigned m, unsigned n) :m_m(m), m_n(n) {} }; - std::stack m_stack; + // fields + std::stack m_stack; public: - typedef vector column_strip; - vector m_vector_of_row_offsets; - indexed_vector m_work_vector; - vector> m_rows; - vector m_columns; + vector m_vector_of_row_offsets; + indexed_vector m_work_vector; + vector> m_rows; + vector m_columns; // starting inner classes class ref { static_matrix & m_matrix; @@ -80,9 +437,9 @@ public: unsigned m_col; public: ref(static_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {} - ref & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; } + ref & operator=(T const & v) { m_matrix.add_new_element( m_row, m_col, v); return *this; } - ref operator=(ref & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } + ref operator=(ref & v) { m_matrix.add_new_element(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } operator T () const { return m_matrix.get_elem(m_row, m_col); } }; @@ -98,7 +455,7 @@ public: public: const T & get_val(const column_cell & c) const { - return m_rows[c.m_i][c.m_offset].get_val(); + return m_rows[c.var()][c.offset()].get_val(); } column_cell & get_column_cell(const row_cell &rc) { @@ -107,7 +464,7 @@ public: void init_row_columns(unsigned m, unsigned n); - // constructor with no parameters + // constructor with no parameters static_matrix() {} // constructor @@ -142,12 +499,12 @@ public: void remove_last_column(unsigned j); - void remove_element(vector> & row, row_cell & elem_to_remove); + void remove_element(row_cell & elem_to_remove); void multiply_column(unsigned column, T const & alpha) { for (auto & t : m_columns[column]) { - auto & r = m_rows[t.m_i][t.m_offset]; - r.m_value *= alpha; + auto & r = m_rows[t.var()].m_cells[t.offset()]; + r.coeff() *= alpha; } } @@ -165,8 +522,6 @@ public: return column_cell(column, offset); } - void set(unsigned row, unsigned col, T const & val); - ref operator()(unsigned row, unsigned col) { return ref(*this, row, col); } std::set> get_domain(); @@ -175,8 +530,8 @@ public: T get_max_abs_in_row(unsigned row) const; void add_column_to_vector (const T & a, unsigned j, T * v) const { - for (const auto & it : m_columns[j]) { - v[it.m_i] += a * get_val(it); + for (const auto & c : m_columns[j]) { + v[c.var()] += a * get_val(c); } } @@ -189,9 +544,6 @@ public: void check_consistency(); #endif - - void cross_out_row(unsigned k); - // void fix_row_indices_in_each_column_for_crossed_row(unsigned k); @@ -202,9 +554,9 @@ public: T get_elem(unsigned i, unsigned j) const; - unsigned number_of_non_zeroes_in_column(unsigned j) const { return m_columns[j].size(); } + unsigned number_of_non_zeroes_in_column(unsigned j) const { return m_columns[j].live_size(); } - unsigned number_of_non_zeroes_in_row(unsigned i) const { return m_rows[i].size(); } + unsigned number_of_non_zeroes_in_row(unsigned i) const { return m_rows[i].live_size(); } unsigned number_of_non_zeroes() const { unsigned ret = 0; @@ -237,12 +589,12 @@ public: m_stack.push(d); } - void pop_row_columns(const vector> & row) { + void pop_row_columns(const row_strip & row) { for (auto & c : row) { - unsigned j = c.m_j; - auto & col = m_columns[j]; - lp_assert(col[col.size() - 1].m_i == m_rows.size() -1 ); // todo : start here!!!! - col.pop_back(); + if (c.dead()) { + continue; + } + m_columns[c.var()].delete_at(c.offset()); } } @@ -272,8 +624,9 @@ public: } void multiply_row(unsigned row, T const & alpha) { - for (auto & t : m_rows[row]) { - t.m_value *= alpha; + for (auto & t : m_rows[row].m_cells) { + if (t.alive()) + t.coeff() *= alpha; } } @@ -286,8 +639,8 @@ public: T dot_product_with_column(const vector & y, unsigned j) const { lp_assert(j < column_count()); T ret = numeric_traits::zero(); - for (auto & it : m_columns[j]) { - ret += y[it.m_i] * get_val(it); // get_value_of_column_cell(it); + for (auto & c : m_columns[j]) { + ret += y[c.var()] * get_val(c); } return ret; } @@ -301,18 +654,20 @@ public: m_rows[i] = m_rows[ii]; m_rows[ii] = t; // now fix the columns - for (auto & rc : m_rows[i]) { - column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lp_assert(cc.m_i == ii); - cc.m_i = i; + for (const auto & rc : m_rows[i]) { + if (rc.dead()) continue; + column_cell & cc = m_columns[rc.var()][rc.offset()]; + lp_assert(cc.var() == ii); + cc.var() = i; } - for (auto & rc : m_rows[ii]) { - column_cell & cc = m_columns[rc.m_j][rc.m_offset]; - lp_assert(cc.m_i == i); - cc.m_i = ii; + for (const auto & rc : m_rows[ii]) { + if (rc.dead()) continue; + column_cell & cc = m_columns[rc.var()][rc.offset()]; + lp_assert(cc.var() == i); + cc.var() = ii; } - } + void fill_last_row_with_pivoting_loop_block(unsigned j, const vector & basis_heading) { int row_index = basis_heading[j]; if (row_index < 0) @@ -322,17 +677,18 @@ public: return; for (const auto & c : m_rows[row_index]) { - if (c.m_j == j) { + if (c.dead()) continue; + if (c.var() == j) { continue; } - T & wv = m_work_vector.m_data[c.m_j]; + T & wv = m_work_vector.m_data[c.var()]; bool was_zero = is_zero(wv); - wv -= alpha * c.m_value; + wv -= alpha * c.coeff(); if (was_zero) - m_work_vector.m_index.push_back(c.m_j); + m_work_vector.m_index.push_back(c.var()); else { if (is_zero(wv)) { - m_work_vector.erase_from_index(c.m_j); + m_work_vector.erase_from_index(c.var()); } } } @@ -350,7 +706,7 @@ public: lp_assert(row_count() > 0); m_work_vector.resize(column_count()); T a; - // we use the form -it + 1 = 0 + // we use the form -it + 1 = 0 m_work_vector.set_value(one_of_type(), bj); for (auto p : row) { m_work_vector.set_value(-p.coeff(), p.var()); @@ -366,10 +722,10 @@ public: unsigned last_row = row_count() - 1; for (unsigned j : m_work_vector.m_index) { - set (last_row, j, m_work_vector.m_data[j]); + add_new_element(last_row, j, m_work_vector.m_data[j]); } lp_assert(column_count() > 0); - set(last_row, column_count() - 1, one_of_type()); + add_new_element(last_row, column_count() - 1, one_of_type()); } void copy_column_to_vector (unsigned j, vector & v) const { @@ -377,7 +733,7 @@ public: for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) - v[it.m_i] = val; + v[it.var()] = val; } } @@ -386,7 +742,8 @@ public: L ret = zero_of_type(); lp_assert(row < m_rows.size()); for (auto & it : m_rows[row]) { - ret += w[it.m_j] * it.get_val(); + if (it.dead()) continue; + ret += w[it.var()] * it.coeff(); } return ret; } @@ -397,9 +754,9 @@ public: // constructor column_cell_plus(const column_cell & c, const static_matrix& A) : m_c(c), m_A(A) {} - unsigned var() const { return m_c.m_i; } - const T & coeff() const { return m_A.m_rows[var()][m_c.m_offset].get_val(); } - + unsigned var() const { return m_c.var(); } + const T & coeff() const { return m_A.m_rows[var()][m_c.offset()].get_val(); } + bool dead() const { return m_c.dead(); } }; struct column_container { @@ -411,7 +768,7 @@ public: // fields const column_cell *m_c; const static_matrix& m_A; - + const column_cell *m_end; //typedefs @@ -425,13 +782,19 @@ public: reference operator*() const { return column_cell_plus(*m_c, m_A); } - self_type operator++() { self_type i = *this; m_c++; return i; } - self_type operator++(int) { m_c++; return *this; } + self_type operator++() { self_type i = *this; + m_c++; + return i; + } + + self_type operator++(int) { + m_c++; + return *this; + } const_iterator(const column_cell* it, const static_matrix& A) : m_c(it), - m_A(A) - {} + m_A(A){} bool operator==(const self_type &other) const { return m_c == other.m_c; } @@ -449,8 +812,32 @@ public: column_container column(unsigned j) const { return column_container(j, *this); + } + void swap_with_head_cell(unsigned j, unsigned offset) { + column_strip & col = m_columns[j]; + column_cell & head = col[0]; + column_cell & cc = col[offset]; + if (head.alive()) { + m_rows[head.var()][head.offset()].offset() = offset; + } + lp_assert(cc.alive()); + m_rows[cc.var()][cc.offset()].offset() = 0; + col.swap_with_head_cell(offset); + } + + + void compress_row_if_needed(unsigned i) { + compress_cells(m_rows[i], m_columns); + lp_assert(is_correct()); + } + + void compress_column_if_needed(unsigned j) { + compress_cells(m_columns[j], m_rows); + lp_assert(is_correct()); + } + ref_row operator[](unsigned i) const { return ref_row(*this, i);} typedef T coefftype; typedef X argtype; diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index 42249b4d8..698363289 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -36,44 +36,54 @@ void static_matrix::init_row_columns(unsigned m, unsigned n) { template void static_matrix::scan_row_ii_to_offset_vector(const row_strip & rvals) { - for (unsigned j = 0; j < rvals.size(); j++) - m_vector_of_row_offsets[rvals[j].m_j] = j; + for (unsigned j = 0; j < rvals.cells_size(); j++) { + if (rvals[j].dead()) continue; + m_vector_of_row_offsets[rvals[j].var()] = j; + } } template bool static_matrix::pivot_row_to_row_given_cell(unsigned i, column_cell & c, unsigned pivot_col) { - unsigned ii = c.m_i; + lp_assert(is_correct()); + unsigned ii = c.var(); lp_assert(i < row_count() && ii < column_count() && i != ii); T alpha = -get_val(c); lp_assert(!is_zero(alpha)); + compress_row_if_needed(ii); auto & rowii = m_rows[ii]; - remove_element(rowii, rowii[c.m_offset]); + remove_element(rowii[c.offset()]); scan_row_ii_to_offset_vector(rowii); - unsigned prev_size_ii = rowii.size(); + unsigned prev_size_ii = rowii.cells_size(); // run over the pivot row and update row ii - for (const auto & iv : m_rows[i]) { - unsigned j = iv.m_j; + for (const auto & iv : m_rows[i].m_cells) { + if (iv.dead()) continue; + unsigned j = iv.var(); if (j == pivot_col) continue; - T alv = alpha * iv.m_value; - lp_assert(!is_zero(iv.m_value)); + lp_assert(!is_zero(iv.coeff())); + T alv = alpha * iv.coeff(); int j_offs = m_vector_of_row_offsets[j]; if (j_offs == -1) { // it is a new element add_new_element(ii, j, alv); } else { - rowii[j_offs].m_value += alv; + rowii[j_offs].coeff() += alv; } } // clean the work vector for (unsigned k = 0; k < prev_size_ii; k++) { - m_vector_of_row_offsets[rowii[k].m_j] = -1; + auto & c = rowii[k]; + if (c.dead()) continue; + m_vector_of_row_offsets[c.var()] = -1; } - // remove zeroes - for (unsigned k = rowii.size(); k-- > 0; ) { - if (is_zero(rowii[k].m_value)) - remove_element(rowii, rowii[k]); + for (unsigned k = rowii.cells_size(); k-- > 0; ) { + auto & c = rowii[k]; + if (c.dead()) + continue; + if (is_zero(c.coeff())) + remove_element(c); } + lp_assert(is_correct()); return !rowii.empty(); } @@ -86,7 +96,7 @@ static_matrix::static_matrix(static_matrix const &A, unsigned * /* basis * init_row_columns(m, m); while (m--) { for (auto & col : A.m_columns[m]){ - set(col.m_i, m, A.get_value_of_column_cell(col)); + set(col.var(), m, A.get_value_of_column_cell(col)); } } } @@ -107,14 +117,14 @@ template void static_matrix::init_empty_matrix init_row_columns(m, n); } -template unsigned static_matrix::lowest_row_in_column(unsigned col) { - lp_assert(col < column_count()); +template unsigned static_matrix::lowest_row_in_column(unsigned col) { column_strip & colstrip = m_columns[col]; - lp_assert(colstrip.size() > 0); + lp_assert(colstrip.live_size() > 0); unsigned ret = 0; - for (auto & t : colstrip) { - if (t.m_i > ret) { - ret = t.m_i; + for (const auto & t : colstrip) { + if (t.dead()) continue; + if (t.var() > ret) { + ret = t.var(); } } return ret; @@ -136,10 +146,10 @@ template void static_matrix::forget_last_colum template void static_matrix::remove_last_column(unsigned j) { column_strip & col = m_columns.back(); for (auto & it : col) { - auto & row = m_rows[it.m_i]; + auto & row = m_rows[it.var()]; unsigned offset = row.size() - 1; for (auto row_it = row.rbegin(); row_it != row.rend(); row_it ++) { - if (row_it->m_j == j) { + if (row_it->var() == j) { row.erase(row.begin() + offset); break; } @@ -150,24 +160,12 @@ template void static_matrix::remove_last_column(u m_vector_of_row_offsets.pop_back(); } - - - -template void static_matrix::set(unsigned row, unsigned col, T const & val) { - if (numeric_traits::is_zero(val)) return; - lp_assert(row < row_count() && col < column_count()); - auto & r = m_rows[row]; - unsigned offs_in_cols = static_cast(m_columns[col].size()); - m_columns[col].push_back(make_column_cell(row, static_cast(r.size()))); - r.push_back(make_row_cell(col, offs_in_cols, val)); -} - template std::set> static_matrix::get_domain() { std::set> ret; for (unsigned i = 0; i < m_rows.size(); i++) { for (auto &it : m_rows[i]) { - ret.insert(std::make_pair(i, it.m_j)); + ret.insert(std::make_pair(i, it.var())); } } return ret; @@ -179,7 +177,7 @@ template void static_matrix::copy_column_to_in for (auto & it : m_columns[j]) { const T& val = get_val(it); if (!is_zero(val)) - v.set_value(val, it.m_i); + v.set_value(val, it.var()); } } @@ -243,7 +241,7 @@ template void static_matrix::check_consistency std::unordered_map, T> by_rows; for (int i = 0; i < m_rows.size(); i++){ for (auto & t : m_rows[i]) { - std::pair p(i, t.m_j); + std::pair p(i, t.var()); lp_assert(by_rows.find(p) == by_rows.end()); by_rows[p] = t.get_val(); } @@ -251,7 +249,7 @@ template void static_matrix::check_consistency std::unordered_map, T> by_cols; for (int i = 0; i < m_columns.size(); i++){ for (auto & t : m_columns[i]) { - std::pair p(t.m_i, i); + std::pair p(t.var(), i); lp_assert(by_cols.find(p) == by_cols.end()); by_cols[p] = get_val(t); } @@ -266,51 +264,10 @@ template void static_matrix::check_consistency } #endif - -template void static_matrix::cross_out_row(unsigned k) { -#ifdef Z3DEBUG - check_consistency(); -#endif - cross_out_row_from_columns(k, m_rows[k]); - fix_row_indices_in_each_column_for_crossed_row(k); - m_rows.erase(m_rows.begin() + k); -#ifdef Z3DEBUG - regen_domain(); - check_consistency(); -#endif -} - - -template void static_matrix::fix_row_indices_in_each_column_for_crossed_row(unsigned k) { - for (unsigned j = 0; j < m_columns.size(); j++) { - auto & col = m_columns[j]; - for (int i = 0; i < col.size(); i++) { - if (col[i].m_i > k) { - col[i].m_i--; - } - } - } -} - -template void static_matrix::cross_out_row_from_columns(unsigned k, row_strip & row) { - for (auto & t : row) { - cross_out_row_from_column(t.m_j, k); - } -} - -template void static_matrix::cross_out_row_from_column(unsigned col, unsigned k) { - auto & s = m_columns[col]; - for (unsigned i = 0; i < s.size(); i++) { - if (s[i].m_i == k) { - s.erase(s.begin() + i); - break; - } - } -} - template T static_matrix::get_elem(unsigned i, unsigned j) const { // should not be used in efficient code !!!! for (auto & t : m_rows[i]) { - if (t.m_j == j) { + if (t.dead()) continue; + if (t.var() == j) { return t.get_val(); } } @@ -342,16 +299,22 @@ template bool static_matrix::is_correct() const { auto &r = m_rows[i]; std::unordered_set s; for (auto & rc : r) { - if (s.find(rc.m_j) != s.end()) { + if (rc.dead()) continue; + if (s.find(rc.var()) != s.end()) { return false; } - s.insert(rc.m_j); - if (rc.m_j >= m_columns.size()) + s.insert(rc.var()); + if (rc.var() >= m_columns.size()) return false; - if (rc.m_offset >= m_columns[rc.m_j].size()) + const auto& col = m_columns[rc.var()]; + if (col.cells_size() <= rc.offset()) return false; - if (rc.get_val() != get_val(m_columns[rc.m_j][rc.m_offset])) + const auto &cc = col[rc.offset()]; + if (cc.dead()) return false; + if (& m_rows[cc.var()][cc.offset()] != & rc) { + return false; + } if (is_zero(rc.get_val())) { return false; } @@ -363,51 +326,56 @@ template bool static_matrix::is_correct() const { auto & c = m_columns[j]; std::unordered_set s; for (auto & cc : c) { - if (s.find(cc.m_i) != s.end()) { + if (cc.dead()) + continue; + if (s.find(cc.var()) != s.end()) { return false; } - s.insert(cc.m_i); - if (cc.m_i >= m_rows.size()) + s.insert(cc.var()); + if (cc.var() >= m_rows.size()) return false; - if (cc.m_offset >= m_rows[cc.m_i].size()) + auto & rc = m_rows[cc.var()][cc.offset()]; + if (rc.dead()) return false; - if (get_val(cc) != m_rows[cc.m_i][cc.m_offset].get_val()) + if (&cc != &m_columns[rc.var()][rc.offset()]) return false; } } - + for (auto & row: m_rows) { + if (! row.is_correct()) + return false; + } + for (auto & col: m_columns) { + if (! col.is_correct()) + return false; + } return true; } template -void static_matrix::remove_element(vector> & row_vals, row_cell & row_el_iv) { - unsigned column_offset = row_el_iv.m_offset; - auto & column_vals = m_columns[row_el_iv.m_j]; - column_cell& cs = m_columns[row_el_iv.m_j][column_offset]; - unsigned row_offset = cs.m_offset; - if (column_offset != column_vals.size() - 1) { - auto & cc = column_vals[column_offset] = column_vals.back(); // copy from the tail - m_rows[cc.m_i][cc.m_offset].m_offset = column_offset; - } - - if (row_offset != row_vals.size() - 1) { - auto & rc = row_vals[row_offset] = row_vals.back(); // copy from the tail - m_columns[rc.m_j][rc.m_offset].m_offset = row_offset; - } - - column_vals.pop_back(); - row_vals.pop_back(); +void static_matrix::remove_element(row_cell & rc) { + lp_assert(rc.alive()); + unsigned j = rc.var(); + unsigned j_offset = rc.offset(); + auto & col = m_columns[j]; + column_cell & c = col[j_offset]; + unsigned i = c.var(); + unsigned i_offset = c.offset(); + col.delete_at(j_offset); + m_rows[i].delete_at(i_offset); } + template -void static_matrix::add_new_element(unsigned row, unsigned col, const T& val) { - auto & row_vals = m_rows[row]; - auto & col_vals = m_columns[col]; - unsigned row_el_offs = static_cast(row_vals.size()); - unsigned col_el_offs = static_cast(col_vals.size()); - row_vals.push_back(row_cell(col, col_el_offs, val)); - col_vals.push_back(column_cell(row, row_el_offs)); +void static_matrix::add_new_element(unsigned i, unsigned j, const T& val) { + auto & row = m_rows[i]; + auto & col = m_columns[j]; + unsigned offset_in_row, offset_in_col; + row_cell& rc = row.add_cell(j, val, offset_in_row); + column_cell& cc = col.add_cell(i, offset_in_col); + rc.offset() = offset_in_col; + cc.offset() = offset_in_row; } } From e9595eb2836a8878000d6b77c08c5b88c02a948a Mon Sep 17 00:00:00 2001 From: Lev Date: Sun, 29 Jul 2018 21:15:42 -0700 Subject: [PATCH 086/118] merge with z3prover Signed-off-by: Lev --- src/tactic/smtlogics/qflia_tactic.cpp | 4 --- src/util/lp/bound_propagator.cpp | 2 -- src/util/lp/lp_core_solver_base_def.h | 2 -- src/util/lp/lp_primal_core_solver.h | 24 +++++++-------- src/util/lp/static_matrix.h | 44 ++------------------------- 5 files changed, 13 insertions(+), 63 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index ad5b660c3..eed4e4425 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -212,9 +212,6 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(preamble_st, -#if 1 - mk_smt_tactic()), -#else or_else(mk_ilp_model_finder_tactic(m), mk_pb_tactic(m), and_then(fail_if_not(mk_is_quasi_pb_probe()), @@ -222,7 +219,6 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()), mk_bounded_tactic(m), mk_smt_tactic())), -#endif main_p); diff --git a/src/util/lp/bound_propagator.cpp b/src/util/lp/bound_propagator.cpp index 199fef9b0..c4fa2aefa 100644 --- a/src/util/lp/bound_propagator.cpp +++ b/src/util/lp/bound_propagator.cpp @@ -16,8 +16,6 @@ const impq & bound_propagator::get_upper_bound(unsigned j) const { return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j]; } void bound_propagator::try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) { - TRACE("try_add_bound", - tout << "v = " << v << ", j = " << j << std::endl;); j = m_lar_solver.adjust_column_index_to_term_index(j); if (m_lar_solver.is_term(j)) { // lp treats terms as not having a free coefficient, restoring it below for the outside consumption diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index ddae7bf20..f9c1ae632 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -108,8 +108,6 @@ pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { if (r.var() != j) m_d[r.var()] -= a * r.get_val(); } -ls - a = zero_of_type(); // zero the pivot column's m_d finally } diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index 2700fc168..d93174bc4 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -280,17 +280,14 @@ public: if (m_bland_mode_tableau) return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); // a short row produces short infeasibility explanation and benefits at least one pivot operation - int choice = -1; - int nchoices = 0; + vector*> choices; + unsigned num_of_non_free_basics = 1000000; unsigned len = 100000000; unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); for (unsigned k = 0; k < this->m_A.m_rows[i].m_cells.size(); k++) { const row_cell& rc = this->m_A.m_rows[i].m_cells[k]; if (rc.dead()) continue; - const row_cell& rc = this->m_A.m_rows[i].m_cells[k]; - if (rc.dead()) continue; ->>>>>>> e6c612f... trying the new scheme in static_matrix : in progress unsigned j = rc.var(); if (j == bj) continue; @@ -305,23 +302,24 @@ public: if (damage < num_of_non_free_basics) { num_of_non_free_basics = damage; len = this->m_A.m_columns[j].live_size(); - choice = k; - nchoices = 1; + choices.clear(); + choices.push_back(&rc); } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % (++nchoices))) { - choice = k; + this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % 2)) { + choices.push_back(&rc); len = this->m_A.m_columns[j].live_size(); } } - if (choice == -1) { + if (choices.size() == 0) { m_inf_row_index_for_tableau = i; return -1; } - const row_cell& rc = this->m_A.m_rows[i].m_cells[choice]; - a_ent = rc.coeff(); - return rc.var(); + const row_cell* rc = choices.size() == 1? choices[0] : + choices[this->m_settings.random_next() % choices.size()]; + a_ent = rc->coeff(); + return rc->var(); } static X positive_infinity() { return convert_struct::convert(std::numeric_limits::max()); diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index 036f628b7..c75fa4ce8 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -64,9 +64,6 @@ public: bool alive() const { return !dead(); } bool dead() const { return m_i == static_cast(-1); } void set_dead() { m_i = -1;} - - - }; template @@ -79,6 +76,7 @@ public: } row_cell(unsigned j, T const & val) : m_j(j), m_value(val) { } + const T & get_val() const { lp_assert(alive()); return m_value; @@ -126,8 +124,6 @@ public: bool alive() const { return !dead(); } bool dead() const { return m_j == static_cast(-1); } void set_dead() { m_j = static_cast(-1); } - - }; template @@ -252,10 +248,6 @@ public: return m_live_size; } - unsigned cells_size() const { - return m_cells.size(); - } - unsigned cells_size() const { return m_cells.size(); } @@ -304,7 +296,7 @@ public: } m_cells.pop_back(); } - + bool is_correct() const { std::set d0; std::set d1; unsigned alive = 0; @@ -341,38 +333,6 @@ public: lp_assert(is_correct()); } - void swap_with_head_cell(unsigned i) { - lp_assert(i > 0); - lp_assert(m_cells[i].alive()); - column_cell head_copy = m_cells[0]; - if (head_copy.dead()) { - if (m_first_dead == 0) { - m_first_dead = i; - } else { - column_cell * c = &m_cells[m_first_dead]; - for (; c->next_dead_index() != 0; c = &m_cells[c->next_dead_index()]); - lp_assert(c->next_dead_index() == 0); - c->next_dead_index() = i; - } - } - m_cells[0] = m_cells[i]; - m_cells[i] = head_copy; - lp_assert(is_correct()); - } - - column_cell & add_cell(unsigned i, unsigned & index) { - if (m_first_dead != -1) { - auto & ret = m_cells[index = m_first_dead]; - m_first_dead = ret.next_dead_index(); - m_live_size++; - ret.var() = i; - return ret; - } - lp_assert(m_live_size == m_cells.size()); - index = m_live_size++; - m_cells.push_back(column_cell(i)); - return m_cells.back(); - } column_cell & add_cell(unsigned i, unsigned & index) { if (m_first_dead != -1) { auto & ret = m_cells[index = m_first_dead]; From 2de27ae3afb727de53b135ec542d51b9205c56a3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 29 Jul 2018 22:33:19 -0700 Subject: [PATCH 087/118] uniform choice of a beneficial column Signed-off-by: Lev Nachmanson --- src/util/lp/lp_primal_core_solver.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index d93174bc4..faf9074f6 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -280,7 +280,8 @@ public: if (m_bland_mode_tableau) return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); // a short row produces short infeasibility explanation and benefits at least one pivot operation - vector*> choices; + int choice = -1; + int nchoices = 0; unsigned num_of_non_free_basics = 1000000; unsigned len = 100000000; unsigned bj = this->m_basis[i]; @@ -302,24 +303,23 @@ public: if (damage < num_of_non_free_basics) { num_of_non_free_basics = damage; len = this->m_A.m_columns[j].live_size(); - choices.clear(); - choices.push_back(&rc); + choice = k; + nchoices = 1; } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % 2)) { - choices.push_back(&rc); + this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % (++nchoices))) { + choice = k; len = this->m_A.m_columns[j].live_size(); } } - if (choices.size() == 0) { + if (choice == -1) { m_inf_row_index_for_tableau = i; return -1; } - const row_cell* rc = choices.size() == 1? choices[0] : - choices[this->m_settings.random_next() % choices.size()]; - a_ent = rc->coeff(); - return rc->var(); + const row_cell& rc = this->m_A.m_rows[i].m_cells[choice]; + a_ent = rc.coeff(); + return rc.var(); } static X positive_infinity() { return convert_struct::convert(std::numeric_limits::max()); From fdcedee8875cd96740330acf0937fa9ba7d3064d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Jul 2018 09:56:16 -0700 Subject: [PATCH 088/118] hardening pop abuse and exception safety for #1776 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 1 + src/solver/combined_solver.cpp | 2 +- src/solver/solver_na2as.cpp | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 6216d6592..f275b0ebf 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2877,6 +2877,7 @@ namespace smt { void context::push() { TRACE("trigger_bug", tout << "context::push()\n";); + scoped_suspend_rlimit _suspend_cancel(m_manager.limit()); pop_to_base_lvl(); setup_context(false); bool was_consistent = !inconsistent(); diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index ad166d425..df494ec42 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -186,7 +186,7 @@ public: void push() override { switch_inc_mode(); m_solver1->push(); - m_solver2->push(); + m_solver2->push(); } void pop(unsigned n) override { diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index db745597c..41853b19a 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -90,9 +90,9 @@ void solver_na2as::push() { void solver_na2as::pop(unsigned n) { if (n > 0) { - pop_core(n); unsigned lvl = m_scopes.size(); - SASSERT(n <= lvl); + n = std::min(lvl, n); + pop_core(n); unsigned new_lvl = lvl - n; restore_assumptions(m_scopes[new_lvl]); m_scopes.shrink(new_lvl); From 9cb713879ef367d44e65ed6dc7089f172ded4348 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 30 Jul 2018 09:56:39 -0700 Subject: [PATCH 089/118] fix the build Signed-off-by: Lev Nachmanson --- src/util/lp/lp_core_solver_base.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 35a989c07..5bde78ca8 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -648,14 +648,6 @@ public: return true; } - int find_pivot_index_in_row(unsigned i, const vector & col) const { - for (const auto & c: col) { - if (c.m_i == i) - return c.m_offset; - } - return -1; - } - void transpose_rows_tableau(unsigned i, unsigned ii); void pivot_to_reduced_costs_tableau(unsigned i, unsigned j); From 181bb60e363e5aaebd87d9286465da8da2ee53a1 Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 30 Jul 2018 12:54:53 -0700 Subject: [PATCH 090/118] remove some lp_asserts Signed-off-by: Lev --- src/util/lp/lp_core_solver_base.h | 1 - src/util/lp/lp_core_solver_base_def.h | 1 - src/util/lp/static_matrix.h | 2 -- src/util/lp/static_matrix_def.h | 4 ++-- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 5bde78ca8..fbb08edfe 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -209,7 +209,6 @@ public: bool need_to_pivot_to_basis_tableau() const { - lp_assert(m_A.is_correct()); unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index f9c1ae632..8cfc39170 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -621,7 +621,6 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { } template bool lp_core_solver_base:: pivot_column_tableau(unsigned j, unsigned piv_row_index) { - lp_assert(m_A.is_correct()); m_A.compress_row_if_needed(piv_row_index); if (!divide_row_by_pivot(piv_row_index, j)) return false; diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index c75fa4ce8..e3ea3c1b0 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -790,12 +790,10 @@ public: void compress_row_if_needed(unsigned i) { compress_cells(m_rows[i], m_columns); - lp_assert(is_correct()); } void compress_column_if_needed(unsigned j) { compress_cells(m_columns[j], m_rows); - lp_assert(is_correct()); } ref_row operator[](unsigned i) const { return ref_row(*this, i);} diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index 698363289..ae0e22540 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -44,7 +44,6 @@ template void static_matrix::scan_row_ii_to_offse template bool static_matrix::pivot_row_to_row_given_cell(unsigned i, column_cell & c, unsigned pivot_col) { - lp_assert(is_correct()); unsigned ii = c.var(); lp_assert(i < row_count() && ii < column_count() && i != ii); T alpha = -get_val(c); @@ -83,7 +82,6 @@ template bool static_matrix::pivot_row_to_row_giv if (is_zero(c.coeff())) remove_element(c); } - lp_assert(is_correct()); return !rowii.empty(); } @@ -295,6 +293,8 @@ template T static_matrix::get_row_balance(unsi } template bool static_matrix::is_correct() const { + if (m_rows.size() > 100 || m_columns.size() > 100) + return true; for (unsigned i = 0; i < m_rows.size(); i++) { auto &r = m_rows[i]; std::unordered_set s; From 0ee68220e1ff210e663434cc3559b9486135188a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 30 Jul 2018 14:34:03 -0700 Subject: [PATCH 091/118] use CASSERT instead of lp_assert for static_matrix Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 2 +- src/util/lp/lp_core_solver_base.h | 2 +- src/util/lp/lp_core_solver_base_def.h | 6 +++--- src/util/lp/static_matrix.h | 8 ++++---- src/util/lp/static_matrix_def.h | 2 -- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 5408bd922..0d8e7f70a 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -1373,7 +1373,7 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { lp_assert(A_r().m_columns[j].live_size() == 0); A_r().m_rows.pop_back(); A_r().m_columns.pop_back(); - lp_assert(A_r().is_correct()); + CASSERT("check_static_matrix", A_r().is_correct()); slv.m_b.pop_back(); } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index fbb08edfe..00ba437d1 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -230,7 +230,7 @@ public: bool reduced_costs_are_correct_tableau() const { if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) return true; - lp_assert(m_A.is_correct()); + CASSERT("check_static_matrix", m_A.is_correct()); if (m_using_infeas_costs) { if (infeasibility_costs_are_correct() == false) { return false; diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index 8cfc39170..6a9af8a26 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -616,7 +616,7 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { } } coeff = one_of_type(); - lp_assert(m_A.is_correct()); + CASSERT("check_static_matrix", m_A.is_correct()); return true; } template bool lp_core_solver_base:: @@ -639,7 +639,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { if (pivot_col_cell_index != 0) m_A.swap_with_head_cell(j, pivot_col_cell_index); - lp_assert(m_A.is_correct()); + CASSERT("check_static_matrix", m_A.is_correct()); while (column.live_size() > 1) { auto & c = column.back(); if (c.dead()) { @@ -655,7 +655,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { } m_A.compress_column_if_needed(j); lp_assert(column.live_size() == 1); - lp_assert(m_A.is_correct()); + CASSERT("check_static_matrix", m_A.is_correct()); if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs) pivot_to_reduced_costs_tableau(piv_row_index, j); diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index e3ea3c1b0..cb6af1379 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -184,7 +184,7 @@ public: c.next_dead_index() = m_first_dead; m_first_dead = j; } - lp_assert(is_correct()); + CASSERT("check_static_matrix", is_correct()); } bool is_correct() const { @@ -264,7 +264,7 @@ public: c.next_dead_index() = m_first_dead; m_first_dead = j; } - lp_assert(is_correct()); + CASSERT("check_static_matrix", is_correct()); } const column_cell& operator[] (unsigned i) const { return m_cells[i];} @@ -330,7 +330,7 @@ public: } m_cells[0] = m_cells[i]; m_cells[i] = head_copy; - lp_assert(is_correct()); + CASSERT("check_static_matrix", is_correct()); } column_cell & add_cell(unsigned i, unsigned & index) { @@ -580,7 +580,7 @@ public: m_columns.pop_back(); // delete the last column m_stack.pop(); } - lp_assert(is_correct()); + CASSERT("check_static_matrix", is_correct()); } void multiply_row(unsigned row, T const & alpha) { diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index ae0e22540..43c91cefa 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -293,8 +293,6 @@ template T static_matrix::get_row_balance(unsi } template bool static_matrix::is_correct() const { - if (m_rows.size() > 100 || m_columns.size() > 100) - return true; for (unsigned i = 0; i < m_rows.size(); i++) { auto &r = m_rows[i]; std::unordered_set s; From 3d274c2e6f58ec4500c0c6f355e007f28d0a03a6 Mon Sep 17 00:00:00 2001 From: Lev Date: Mon, 30 Jul 2018 15:55:06 -0700 Subject: [PATCH 092/118] use CASSERT for hnf Signed-off-by: Lev --- src/util/lp/hnf.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/util/lp/hnf.h b/src/util/lp/hnf.h index 3cdeac466..8edce39e0 100644 --- a/src/util/lp/hnf.h +++ b/src/util/lp/hnf.h @@ -317,7 +317,6 @@ class hnf { } void handle_column_ij_in_row_i(unsigned i, unsigned j) { - lp_assert(is_correct_modulo()); const mpq& aii = m_H[i][i]; const mpq& aij = m_H[i][j]; mpq p,q,r; @@ -342,7 +341,7 @@ class hnf { // from the left multiply_U_reverse_from_left_by(i, j, aii_over_r, aij_over_r, -q, p); - lp_assert(is_correct_modulo()); + CASSERT("hnf_test", is_correct_modulo()); } @@ -402,8 +401,6 @@ class hnf { } void process_row(unsigned i) { - - lp_assert(is_correct_modulo()); for (unsigned j = i + 1; j < m_n; j++) { process_row_column(i, j); } @@ -414,7 +411,7 @@ class hnf { if (is_neg(m_H[i][i])) switch_sign_for_column(i); work_on_columns_less_than_i_in_the_triangle(i); - lp_assert(is_correct_modulo()); + CASSERT("hnf_test", is_correct_modulo()); } void calculate() { @@ -604,7 +601,7 @@ public: #ifdef Z3DEBUG prepare_U_and_U_reverse(); calculate(); - lp_assert(is_correct_final()); + CASSERT("hnf_test", is_correct_final()); #endif calculate_by_modulo(); #ifdef Z3DEBUG From 22fc5ad771a8de5e7afbfc7b2365404c250121fb Mon Sep 17 00:00:00 2001 From: Sosuke MORIGUCHI Date: Tue, 31 Jul 2018 21:39:02 +0900 Subject: [PATCH 093/118] Modify javadoc directive and mis-capitalization of method name --- src/api/java/Context.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 07be64230..57085a09e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2505,7 +2505,7 @@ public class Context implements AutoCloseable { * with the sorts of the bound variables, {@code names} is an array with the * 'names' of the bound variables, and {@code body} is the body of the * lambda. - * Note that the bound variables are de-Bruijn indices created using {@see #MkBound} + * Note that the bound variables are de-Bruijn indices created using {@link #mkBound} * Z3 applies the convention that the last element in {@code names} and * {@code sorts} refers to the variable with index 0, the second to last element * of {@code names} and {@code sorts} refers to the variable From 42d30e3eddcfff602da327db907fe3dc699c78d5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 08:20:14 -0700 Subject: [PATCH 094/118] remove availability of divides as it clashes with user-defined functions in benchmarks Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 3c5e2e1c0..db3604a99 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -549,7 +549,8 @@ void arith_decl_plugin::get_op_names(svector& op_names, symbol con op_names.push_back(builtin_name("*",OP_MUL)); op_names.push_back(builtin_name("/",OP_DIV)); op_names.push_back(builtin_name("div",OP_IDIV)); - op_names.push_back(builtin_name("divides",OP_IDIVIDES)); + // clashes with user-defined functions + // op_names.push_back(builtin_name("divides",OP_IDIVIDES)); op_names.push_back(builtin_name("rem",OP_REM)); op_names.push_back(builtin_name("mod",OP_MOD)); op_names.push_back(builtin_name("to_real",OP_TO_REAL)); From 98d42421bc5232bfe9a0f669d7227505bc816d37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 08:42:19 -0700 Subject: [PATCH 095/118] harness more pop uses Signed-off-by: Nikolaj Bjorner --- src/solver/tactic2solver.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 135d402e6..85d3b483d 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -125,6 +125,7 @@ void tactic2solver::push_core() { } void tactic2solver::pop_core(unsigned n) { + n = std::min(m_scopes.size(), n); unsigned new_lvl = m_scopes.size() - n; unsigned old_sz = m_scopes[new_lvl]; m_assertions.shrink(old_sz); @@ -142,9 +143,8 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_tactic->updt_params(get_params()); // parameters are allowed to overwrite logic. goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores); - unsigned sz = m_assertions.size(); - for (unsigned i = 0; i < sz; i++) { - g->assert_expr(m_assertions.get(i)); + for (expr* e : m_assertions) { + g->assert_expr(e); } for (unsigned i = 0; i < num_assumptions; i++) { proof_ref pr(m.mk_asserted(assumptions[i]), m); From c7898b19770d782e7d63bef9a1b7623b9097091d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 14:22:57 -0700 Subject: [PATCH 096/118] trace push/pop Signed-off-by: Nikolaj Bjorner --- src/solver/combined_solver.cpp | 2 ++ src/solver/tactic2solver.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index df494ec42..61094c29c 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -187,9 +187,11 @@ public: switch_inc_mode(); m_solver1->push(); m_solver2->push(); + TRACE("pop", tout << "push\n";); } void pop(unsigned n) override { + TRACE("pop", tout << n << "\n";); switch_inc_mode(); m_solver1->pop(n); m_solver2->pop(n); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 85d3b483d..0c791fe5a 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -122,9 +122,11 @@ void tactic2solver::assert_expr_core(expr * t) { void tactic2solver::push_core() { m_scopes.push_back(m_assertions.size()); m_result = nullptr; + TRACE("pop", tout << m_scopes.size() << "\n";); } void tactic2solver::pop_core(unsigned n) { + TRACE("pop", tout << m_scopes.size() << " " << n << "\n";); n = std::min(m_scopes.size(), n); unsigned new_lvl = m_scopes.size() - n; unsigned old_sz = m_scopes[new_lvl]; From 114f31c16aac093e837de0f071e354ba9a2ef20a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 15:12:46 -0700 Subject: [PATCH 097/118] do not update assertions within scopes Signed-off-by: Nikolaj Bjorner --- src/solver/tactic2solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 0c791fe5a..cf0c6f9bc 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -171,7 +171,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass m_result->set_status(l_undef); if (reason_unknown != "") m_result->m_unknown = reason_unknown; - if (num_assumptions == 0) { + if (num_assumptions == 0 && m_scopes.empty()) { m_assertions.reset(); g->get_formulas(m_assertions); } From 22a5687e1664be2f82f60fe166c3d2e950664584 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 15:52:21 -0700 Subject: [PATCH 098/118] supply bits on demand Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 34 +++++++++++++++++++++++++++++----- src/smt/theory_bv.h | 7 ++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index a0c62b959..cff306975 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -162,10 +162,14 @@ namespace smt { if (v == null_theory_var) { v = mk_var(n); } + ensure_bits(v); + return v; + } + + void theory_bv::ensure_bits(theory_var v) { if (m_bits[v].empty()) { mk_bits(v); } - return v; } enode * theory_bv::get_arg(enode * n, unsigned idx) { @@ -186,6 +190,7 @@ namespace smt { void theory_bv::get_bits(theory_var v, expr_ref_vector & r) { context & ctx = get_context(); + ensure_bits(v); literal_vector & bits = m_bits[v]; for (literal lit : bits) { expr_ref l(get_manager()); @@ -223,6 +228,7 @@ namespace smt { \brief v1[idx] = ~v2[idx], then v1 /= v2 is a theory axiom. */ void theory_bv::mk_new_diseq_axiom(theory_var v1, theory_var v2, unsigned idx) { + ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1][idx] == ~m_bits[v2][idx]); TRACE("bv_diseq_axiom", tout << "found new diseq axiom\n"; display_var(tout, v1); display_var(tout, v2);); // found new disequality @@ -241,6 +247,7 @@ namespace smt { } void theory_bv::register_true_false_bit(theory_var v, unsigned idx) { + ensure_bits(v); SASSERT(m_bits[v][idx] == true_literal || m_bits[v][idx] == false_literal); bool is_true = (m_bits[v][idx] == true_literal); zero_one_bits & bits = m_zero_one_bits[v]; @@ -251,11 +258,13 @@ namespace smt { \brief v[idx] = ~v'[idx], then v /= v' is a theory axiom. */ void theory_bv::find_new_diseq_axioms(var_pos_occ * occs, theory_var v, unsigned idx) { + ensure_bits(v); literal l = m_bits[v][idx]; l.neg(); while (occs) { theory_var v2 = occs->m_var; unsigned idx2 = occs->m_idx; + ensure_bits(v2); if (idx == idx2 && m_bits[v2][idx2] == l && get_bv_size(v2) == get_bv_size(v)) mk_new_diseq_axiom(v, v2, idx); occs = occs->m_next; @@ -267,6 +276,7 @@ namespace smt { */ void theory_bv::add_bit(theory_var v, literal l) { context & ctx = get_context(); + ensure_bits(v); literal_vector & bits = m_bits[v]; unsigned idx = bits.size(); bits.push_back(l); @@ -329,6 +339,7 @@ namespace smt { */ void theory_bv::find_wpos(theory_var v) { context & ctx = get_context(); + ensure_bits(v); literal_vector const & bits = m_bits[v]; unsigned sz = bits.size(); unsigned & wpos = m_wpos[v]; @@ -435,6 +446,7 @@ namespace smt { tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << " " << ctx.get_scope_level() << "\n";); literal_vector eqs; + ensure_bits(v1); ensure_bits(v2); for (unsigned i = 0; i < sz; ++i) { literal l1 = m_bits[v1][i]; literal l2 = m_bits[v2][i]; @@ -487,7 +499,7 @@ namespace smt { } } - bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { + bool theory_bv::get_fixed_value(theory_var v, numeral & result) const { context & ctx = get_context(); result.reset(); literal_vector const & bits = m_bits[v]; @@ -844,6 +856,7 @@ namespace smt { unsigned start = n->get_decl()->get_parameter(1).get_int(); unsigned end = n->get_decl()->get_parameter(0).get_int(); SASSERT(start <= end); + ensure_bits(arg); literal_vector & arg_bits = m_bits[arg]; m_bits[v].reset(); for (unsigned i = start; i <= end; ++i) @@ -1109,6 +1122,7 @@ namespace smt { void theory_bv::new_diseq_eh(theory_var v1, theory_var v2) { if (is_bv(v1)) { + ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1].size() == m_bits[v2].size()); expand_diseq(v1, v2); } @@ -1124,6 +1138,7 @@ namespace smt { literal_vector & lits = m_tmp_literals; lits.reset(); lits.push_back(mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), true)); + ensure_bits(v1); ensure_bits(v2); literal_vector const & bits1 = m_bits[v1]; literal_vector::const_iterator it1 = bits1.begin(); literal_vector::const_iterator end1 = bits1.end(); @@ -1190,6 +1205,7 @@ namespace smt { if (m_wpos[v] == idx) find_wpos(v); + ensure_bits(v); literal_vector & bits = m_bits[v]; literal bit = bits[idx]; lbool val = ctx.get_assignment(bit); @@ -1204,6 +1220,7 @@ namespace smt { antecedent.neg(); } while (v2 != v) { + ensure_bits(v2); literal_vector & bits2 = m_bits[v2]; literal bit2 = bits2[idx]; SASSERT(bit != ~bit2); @@ -1234,6 +1251,7 @@ namespace smt { m_stats.m_num_bit2core++; context & ctx = get_context(); SASSERT(ctx.get_assignment(antecedent) == l_true); + ensure_bits(v2); SASSERT(m_bits[v2][idx].var() == consequent.var()); SASSERT(consequent.var() != antecedent.var()); TRACE("bv_bit_prop", tout << "assigning: "; ctx.display_literal(tout, consequent); @@ -1304,6 +1322,7 @@ namespace smt { enode * e = ctx.get_enode(n); theory_var v = e->get_th_var(get_id()); if (v != null_theory_var) { + ensure_bits(v); literal_vector & bits = m_bits[v]; for (literal lit : bits) { ctx.mark_as_relevant(lit); @@ -1385,6 +1404,7 @@ namespace smt { } m_prop_queue.reset(); context & ctx = get_context(); + ensure_bits(v1); ensure_bits(v2); literal_vector & bits1 = m_bits[v1]; literal_vector & bits2 = m_bits[v2]; SASSERT(bits1.size() == bits2.size()); @@ -1471,6 +1491,7 @@ namespace smt { theory_var v1 = m_merge_aux[!zo.m_is_true][zo.m_idx]; if (v1 != null_theory_var) { // conflict was detected ... v1 and v2 have complementary bits + ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1][zo.m_idx] == ~(m_bits[v2][zo.m_idx])); SASSERT(m_bits[v1].size() == m_bits[v2].size()); mk_new_diseq_axiom(v1, v2, zo.m_idx); @@ -1654,7 +1675,7 @@ namespace smt { } #ifdef Z3DEBUG - bool theory_bv::check_assignment(theory_var v) const { + bool theory_bv::check_assignment(theory_var v) { context & ctx = get_context(); if (!is_root(v)) return true; @@ -1663,9 +1684,11 @@ namespace smt { } theory_var v2 = v; + ensure_bits(v2); literal_vector const & bits2 = m_bits[v2]; theory_var v1 = v2; do { + ensure_bits(v1); literal_vector const & bits1 = m_bits[v1]; SASSERT(bits1.size() == bits2.size()); unsigned sz = bits1.size(); @@ -1695,7 +1718,7 @@ namespace smt { \remark The method does nothing if v is not the root of the equivalence class. */ - bool theory_bv::check_zero_one_bits(theory_var v) const { + bool theory_bv::check_zero_one_bits(theory_var v) { if (get_context().inconsistent()) return true; // property is only valid if the context is not in a conflict. if (is_root(v) && is_bv(v)) { @@ -1706,6 +1729,7 @@ namespace smt { bits[1].resize(bv_sz, false); theory_var curr = v; do { + ensure_bits(curr); literal_vector const & lits = m_bits[curr]; for (unsigned i = 0; i < lits.size(); i++) { literal l = lits[i]; @@ -1736,7 +1760,7 @@ namespace smt { return true; } - bool theory_bv::check_invariant() const { + bool theory_bv::check_invariant() { unsigned num = get_num_vars(); for (unsigned v = 0; v < num; v++) { check_assignment(v); diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index f2e0f5bed..9e868a887 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -141,6 +141,7 @@ namespace smt { bool is_numeral(theory_var v) const { return m_util.is_numeral(get_enode(v)->get_owner()); } app * mk_bit2bool(app * bv, unsigned idx); + void ensure_bits(theory_var v); void mk_bits(theory_var v); friend class mk_atom_trail; void mk_bit2bool(app * n); @@ -266,9 +267,9 @@ namespace smt { #ifdef Z3DEBUG - bool check_assignment(theory_var v) const; - bool check_invariant() const; - bool check_zero_one_bits(theory_var v) const; + bool check_assignment(theory_var v); + bool check_invariant(); + bool check_zero_one_bits(theory_var v); #endif }; }; From 4b00d6aef2b1808980de280477c5adaa0e0567f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 16:13:25 -0700 Subject: [PATCH 099/118] move mk-bits to mk-var Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 31 ++----------------------------- src/smt/theory_bv.h | 1 - 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index cff306975..70438d1b1 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -37,6 +37,7 @@ namespace smt { m_wpos.push_back(0); m_zero_one_bits.push_back(zero_one_bits()); get_context().attach_th_var(n, this, r); + mk_bits(r); return r; } @@ -162,16 +163,9 @@ namespace smt { if (v == null_theory_var) { v = mk_var(n); } - ensure_bits(v); return v; } - void theory_bv::ensure_bits(theory_var v) { - if (m_bits[v].empty()) { - mk_bits(v); - } - } - enode * theory_bv::get_arg(enode * n, unsigned idx) { if (m_params.m_bv_reflect) { return n->get_arg(idx); @@ -190,7 +184,6 @@ namespace smt { void theory_bv::get_bits(theory_var v, expr_ref_vector & r) { context & ctx = get_context(); - ensure_bits(v); literal_vector & bits = m_bits[v]; for (literal lit : bits) { expr_ref l(get_manager()); @@ -228,7 +221,6 @@ namespace smt { \brief v1[idx] = ~v2[idx], then v1 /= v2 is a theory axiom. */ void theory_bv::mk_new_diseq_axiom(theory_var v1, theory_var v2, unsigned idx) { - ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1][idx] == ~m_bits[v2][idx]); TRACE("bv_diseq_axiom", tout << "found new diseq axiom\n"; display_var(tout, v1); display_var(tout, v2);); // found new disequality @@ -247,7 +239,6 @@ namespace smt { } void theory_bv::register_true_false_bit(theory_var v, unsigned idx) { - ensure_bits(v); SASSERT(m_bits[v][idx] == true_literal || m_bits[v][idx] == false_literal); bool is_true = (m_bits[v][idx] == true_literal); zero_one_bits & bits = m_zero_one_bits[v]; @@ -258,13 +249,11 @@ namespace smt { \brief v[idx] = ~v'[idx], then v /= v' is a theory axiom. */ void theory_bv::find_new_diseq_axioms(var_pos_occ * occs, theory_var v, unsigned idx) { - ensure_bits(v); literal l = m_bits[v][idx]; l.neg(); while (occs) { theory_var v2 = occs->m_var; unsigned idx2 = occs->m_idx; - ensure_bits(v2); if (idx == idx2 && m_bits[v2][idx2] == l && get_bv_size(v2) == get_bv_size(v)) mk_new_diseq_axiom(v, v2, idx); occs = occs->m_next; @@ -276,7 +265,6 @@ namespace smt { */ void theory_bv::add_bit(theory_var v, literal l) { context & ctx = get_context(); - ensure_bits(v); literal_vector & bits = m_bits[v]; unsigned idx = bits.size(); bits.push_back(l); @@ -339,7 +327,6 @@ namespace smt { */ void theory_bv::find_wpos(theory_var v) { context & ctx = get_context(); - ensure_bits(v); literal_vector const & bits = m_bits[v]; unsigned sz = bits.size(); unsigned & wpos = m_wpos[v]; @@ -446,7 +433,6 @@ namespace smt { tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << " " << ctx.get_scope_level() << "\n";); literal_vector eqs; - ensure_bits(v1); ensure_bits(v2); for (unsigned i = 0; i < sz; ++i) { literal l1 = m_bits[v1][i]; literal l2 = m_bits[v2][i]; @@ -856,7 +842,6 @@ namespace smt { unsigned start = n->get_decl()->get_parameter(1).get_int(); unsigned end = n->get_decl()->get_parameter(0).get_int(); SASSERT(start <= end); - ensure_bits(arg); literal_vector & arg_bits = m_bits[arg]; m_bits[v].reset(); for (unsigned i = start; i <= end; ++i) @@ -1107,8 +1092,7 @@ namespace smt { void theory_bv::apply_sort_cnstr(enode * n, sort * s) { if (!is_attached_to_var(n) && !approximate_term(n->get_owner())) { - theory_var v = mk_var(n); - mk_bits(v); + mk_var(n); } } @@ -1122,7 +1106,6 @@ namespace smt { void theory_bv::new_diseq_eh(theory_var v1, theory_var v2) { if (is_bv(v1)) { - ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1].size() == m_bits[v2].size()); expand_diseq(v1, v2); } @@ -1138,7 +1121,6 @@ namespace smt { literal_vector & lits = m_tmp_literals; lits.reset(); lits.push_back(mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), true)); - ensure_bits(v1); ensure_bits(v2); literal_vector const & bits1 = m_bits[v1]; literal_vector::const_iterator it1 = bits1.begin(); literal_vector::const_iterator end1 = bits1.end(); @@ -1205,7 +1187,6 @@ namespace smt { if (m_wpos[v] == idx) find_wpos(v); - ensure_bits(v); literal_vector & bits = m_bits[v]; literal bit = bits[idx]; lbool val = ctx.get_assignment(bit); @@ -1220,7 +1201,6 @@ namespace smt { antecedent.neg(); } while (v2 != v) { - ensure_bits(v2); literal_vector & bits2 = m_bits[v2]; literal bit2 = bits2[idx]; SASSERT(bit != ~bit2); @@ -1251,7 +1231,6 @@ namespace smt { m_stats.m_num_bit2core++; context & ctx = get_context(); SASSERT(ctx.get_assignment(antecedent) == l_true); - ensure_bits(v2); SASSERT(m_bits[v2][idx].var() == consequent.var()); SASSERT(consequent.var() != antecedent.var()); TRACE("bv_bit_prop", tout << "assigning: "; ctx.display_literal(tout, consequent); @@ -1322,7 +1301,6 @@ namespace smt { enode * e = ctx.get_enode(n); theory_var v = e->get_th_var(get_id()); if (v != null_theory_var) { - ensure_bits(v); literal_vector & bits = m_bits[v]; for (literal lit : bits) { ctx.mark_as_relevant(lit); @@ -1404,7 +1382,6 @@ namespace smt { } m_prop_queue.reset(); context & ctx = get_context(); - ensure_bits(v1); ensure_bits(v2); literal_vector & bits1 = m_bits[v1]; literal_vector & bits2 = m_bits[v2]; SASSERT(bits1.size() == bits2.size()); @@ -1491,7 +1468,6 @@ namespace smt { theory_var v1 = m_merge_aux[!zo.m_is_true][zo.m_idx]; if (v1 != null_theory_var) { // conflict was detected ... v1 and v2 have complementary bits - ensure_bits(v1); ensure_bits(v2); SASSERT(m_bits[v1][zo.m_idx] == ~(m_bits[v2][zo.m_idx])); SASSERT(m_bits[v1].size() == m_bits[v2].size()); mk_new_diseq_axiom(v1, v2, zo.m_idx); @@ -1684,11 +1660,9 @@ namespace smt { } theory_var v2 = v; - ensure_bits(v2); literal_vector const & bits2 = m_bits[v2]; theory_var v1 = v2; do { - ensure_bits(v1); literal_vector const & bits1 = m_bits[v1]; SASSERT(bits1.size() == bits2.size()); unsigned sz = bits1.size(); @@ -1729,7 +1703,6 @@ namespace smt { bits[1].resize(bv_sz, false); theory_var curr = v; do { - ensure_bits(curr); literal_vector const & lits = m_bits[curr]; for (unsigned i = 0; i < lits.size(); i++) { literal l = lits[i]; diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 9e868a887..23644c6fd 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -141,7 +141,6 @@ namespace smt { bool is_numeral(theory_var v) const { return m_util.is_numeral(get_enode(v)->get_owner()); } app * mk_bit2bool(app * bv, unsigned idx); - void ensure_bits(theory_var v); void mk_bits(theory_var v); friend class mk_atom_trail; void mk_bit2bool(app * n); From 124e963b10d25d711c7c951be862ad81fa926de7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 31 Jul 2018 16:26:41 -0700 Subject: [PATCH 100/118] revert bit-resize issues Signed-off-by: Nikolaj Bjorner --- src/smt/theory_bv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 70438d1b1..e693c4531 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -37,7 +37,6 @@ namespace smt { m_wpos.push_back(0); m_zero_one_bits.push_back(zero_one_bits()); get_context().attach_th_var(n, this, r); - mk_bits(r); return r; } @@ -162,6 +161,7 @@ namespace smt { theory_var v = n->get_th_var(get_id()); if (v == null_theory_var) { v = mk_var(n); + mk_bits(v); } return v; } @@ -1092,7 +1092,7 @@ namespace smt { void theory_bv::apply_sort_cnstr(enode * n, sort * s) { if (!is_attached_to_var(n) && !approximate_term(n->get_owner())) { - mk_var(n); + mk_bits(mk_var(n)); } } From 0a5141780431b8f4af8e4c44ca4da5aa864645a1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 31 Jul 2018 22:51:27 -0700 Subject: [PATCH 101/118] unroll static_matrix to avoid dead cells Signed-off-by: Lev Nachmanson --- src/util/lp/bound_analyzer_on_row.h | 8 - src/util/lp/int_solver.cpp | 11 - src/util/lp/lar_core_solver.h | 5 +- src/util/lp/lar_core_solver_def.h | 3 +- src/util/lp/lar_solver.cpp | 29 +- src/util/lp/lp_core_solver_base.h | 7 +- src/util/lp/lp_core_solver_base_def.h | 44 +- src/util/lp/lp_primal_core_solver.h | 22 +- src/util/lp/lp_primal_core_solver_def.h | 2 +- .../lp/lp_primal_core_solver_tableau_def.h | 11 +- src/util/lp/random_updater_def.h | 3 +- src/util/lp/static_matrix.cpp | 9 +- src/util/lp/static_matrix.h | 502 +++--------------- src/util/lp/static_matrix_def.h | 168 +++--- 14 files changed, 231 insertions(+), 593 deletions(-) diff --git a/src/util/lp/bound_analyzer_on_row.h b/src/util/lp/bound_analyzer_on_row.h index 3d047cd86..549c8e5ce 100644 --- a/src/util/lp/bound_analyzer_on_row.h +++ b/src/util/lp/bound_analyzer_on_row.h @@ -59,8 +59,6 @@ public : unsigned j; void analyze() { for (const auto & c : m_row) { - if (c.dead()) - continue; if ((m_column_of_l == -2) && (m_column_of_u == -2)) break; analyze_bound_on_var_on_coeff(c.var(), c.coeff()); @@ -170,7 +168,6 @@ public : mpq total; lp_assert(is_zero(total)); for (const auto& p : m_row) { - if (p.dead()) continue; bool str; total -= monoid_min(p.coeff(), p.var(), str); if (str) @@ -179,7 +176,6 @@ public : for (const auto &p : m_row) { - if (p.dead()) continue; bool str; bool a_is_pos = is_pos(p.coeff()); mpq bound = total / p.coeff() + monoid_min_no_mult(a_is_pos, p.var(), str); @@ -197,7 +193,6 @@ public : mpq total; lp_assert(is_zero(total)); for (const auto &p : m_row) { - if (p.dead()) continue; bool str; total -= monoid_max(p.coeff(), p.var(), str); if (str) @@ -205,7 +200,6 @@ public : } for (const auto& p : m_row) { - if (p.dead()) continue; bool str; bool a_is_pos = is_pos(p.coeff()); mpq bound = total / p.coeff() + monoid_max_no_mult(a_is_pos, p.var(), str); @@ -228,7 +222,6 @@ public : mpq bound = -m_rs.x; bool strict = false; for (const auto& p : m_row) { - if (p.dead()) continue; j = p.var(); if (j == static_cast(m_column_of_u)) { u_coeff = p.coeff(); @@ -258,7 +251,6 @@ public : mpq bound = -m_rs.x; bool strict = false; for (const auto &p : m_row) { - if (p.dead()) continue; j = p.var(); if (j == static_cast(m_column_of_l)) { l_coeff = p.coeff(); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 78206dc53..a77c202a0 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -100,7 +100,6 @@ bool int_solver::is_gomory_cut_target(const row_strip& row) { // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). unsigned j; for (const auto & p : row) { - if (p.dead()) continue; j = p.var(); if (is_base(j)) continue; if (!at_bound(j)) @@ -312,7 +311,6 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row TRACE("gomory_cut", tout << "applying cut at:\n"; m_lar_solver->print_row(row, tout); tout << std::endl; for (auto & p : row) { - if (p.dead()) continue; m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(p.var(), tout); } tout << "inf_col = " << inf_col << std::endl; @@ -327,7 +325,6 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row mpq f_0 = int_solver::fractional_part(get_value(inf_col)); mpq one_min_f_0 = 1 - f_0; for (const auto & p : row) { - if (p.dead()) continue; x_j = p.var(); if (x_j == inf_col) continue; @@ -356,7 +353,6 @@ lia_move int_solver::mk_gomory_cut( unsigned inf_col, const row_strip & row int int_solver::find_free_var_in_gomory_row(const row_strip& row) { unsigned j; for (const auto & p : row) { - if (p.dead()) continue; j = p.var(); if (!is_base(j) && is_free(j)) return static_cast(j); @@ -793,7 +789,6 @@ lia_move int_solver::patch_nbasic_columns() { mpq get_denominators_lcm(const row_strip & row) { mpq r(1); for (auto & c : row) { - if (c.dead()) continue; r = lcm(r, denominator(c.coeff())); } return r; @@ -807,7 +802,6 @@ bool int_solver::gcd_test_for_row(static_matrix> & A, uns bool least_coeff_is_bounded = false; unsigned j; for (auto &c : A.m_rows[i]) { - if (c.dead()) continue; j = c.var(); const mpq& a = c.coeff(); if (m_lar_solver->column_is_fixed(j)) { @@ -873,7 +867,6 @@ void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j) { } void int_solver::fill_explanation_from_fixed_columns(const row_strip & row) { for (const auto & c : row) { - if (c.dead()) continue; if (!m_lar_solver->column_is_fixed(c.var())) continue; add_to_explanation_from_fixed_or_boxed_column(c.var()); @@ -899,7 +892,6 @@ bool int_solver::ext_gcd_test(const row_strip & row, mpq a; unsigned j; for (const auto & c : row) { - if (c.dead()) continue; j = c.var(); const mpq & a = c.coeff(); if (m_lar_solver->column_is_fixed(j)) @@ -1031,7 +1023,6 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq lp_assert(settings().use_tableau()); const auto & A = m_lar_solver->A_r(); for (const auto &c : A.column(j)) { - if (c.dead()) continue; row_index = c.var(); const mpq & a = c.coeff(); @@ -1162,14 +1153,12 @@ bool int_solver::at_upper(unsigned j) const { void int_solver::display_row_info(std::ostream & out, unsigned row_index) const { auto & rslv = m_lar_solver->m_mpq_lar_core_solver.m_r_solver; for (const auto &c: rslv.m_A.m_rows[row_index]) { - if (c.dead()) continue; if (numeric_traits::is_pos(c.coeff())) out << "+"; out << c.coeff() << rslv.column_name(c.var()) << " "; } for (const auto& c: rslv.m_A.m_rows[row_index]) { - if (c.dead()) continue; rslv.print_column_bound_info(c.var(), out); } rslv.print_column_bound_info(rslv.m_basis[row_index], out); diff --git a/src/util/lp/lar_core_solver.h b/src/util/lp/lar_core_solver.h index 4223f5964..904550339 100644 --- a/src/util/lp/lar_core_solver.h +++ b/src/util/lp/lar_core_solver.h @@ -583,7 +583,7 @@ public: if (!m_r_solver.m_settings.use_tableau()) return true; for (unsigned j : m_r_solver.m_basis) { - lp_assert(m_r_solver.m_A.m_columns[j].live_size() == 1); + lp_assert(m_r_solver.m_A.m_columns[j].size() == 1); } for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) { if (m_r_solver.m_basis_heading[j] >= 0) continue; @@ -632,8 +632,7 @@ public: void create_double_matrix(static_matrix & A) { for (unsigned i = 0; i < m_r_A.row_count(); i++) { auto & row = m_r_A.m_rows[i]; - for (row_cell & c : row.m_cells) { - if (c.dead()) continue; + for (row_cell & c : row) { A.add_new_element(i, c.var(), c.get_val().get_double()); } } diff --git a/src/util/lp/lar_core_solver_def.h b/src/util/lp/lar_core_solver_def.h index c626362fc..b945b0e51 100644 --- a/src/util/lp/lar_core_solver_def.h +++ b/src/util/lp/lar_core_solver_def.h @@ -226,8 +226,7 @@ void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); m_infeasible_linear_combination.clear(); - for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau].m_cells) { - if (rc.dead()) continue; + for (auto & rc : m_r_solver.m_A.m_rows[m_r_solver.m_inf_row_index_for_tableau]) { m_infeasible_linear_combination.push_back(std::make_pair( rc.get_val(), rc.var())); } } diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 0d8e7f70a..78bd45e94 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -162,7 +162,7 @@ void lar_solver::analyze_new_bounds_on_row_tableau( unsigned row_index, bound_propagator & bp ) { - if (A_r().m_rows[row_index].live_size() > settings().max_row_length_for_bound_propagation) + if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation) return; lp_assert(use_tableau()); bound_analyzer_on_row>::analyze_row(A_r().m_rows[row_index], @@ -215,7 +215,6 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp bound_j = m_var_register.external_to_local(bound_j); } for (auto const& r : A_r().m_rows[i]) { - if (r.dead()) continue; unsigned j = r.var(); if (j == bound_j) continue; mpq const& a = r.get_val(); @@ -429,7 +428,6 @@ void lar_solver::set_costs_to_zero(const lar_term& term) { jset.insert(j); else { for (const auto & rc : A_r().m_rows[i]) - if (rc.alive()) jset.insert(rc.var()); } } @@ -640,8 +638,7 @@ void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { for (auto & rc : m_mpq_lar_core_solver.m_r_A.m_columns[j]) - if (rc.alive()) - m_rows_with_changed_bounds.insert(rc.var()); + m_rows_with_changed_bounds.insert(rc.var()); } bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } @@ -670,7 +667,6 @@ void lar_solver::adjust_x_of_column(unsigned j) { bool lar_solver::row_is_correct(unsigned i) const { numeric_pair r = zero_of_type>(); for (const auto & c : A_r().m_rows[i]) { - if (c.dead()) continue; r += c.coeff() * m_mpq_lar_core_solver.m_r_x[c.var()]; } return is_zero(r); @@ -695,7 +691,6 @@ bool lar_solver::costs_are_used() const { void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta) { if (use_tableau()) { for (const auto & c : A_r().m_columns[j]) { - if (c.dead()) continue; unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; if (tableau_with_costs()) { m_basic_columns_with_changed_cost.insert(bj); @@ -871,7 +866,7 @@ void lar_solver::fill_last_row_of_A_r(static_matrix> & A, lp_assert(A.row_count() > 0); lp_assert(A.column_count() > 0); unsigned last_row = A.row_count() - 1; - lp_assert(A.m_rows[last_row].live_size() == 0); + lp_assert(A.m_rows[last_row].size() == 0); for (auto & t : ls->m_coeffs) { lp_assert(!is_zero(t.second)); var_index j = t.first; @@ -1332,9 +1327,8 @@ void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsign lp_assert(A_r().row_count() == i + 1 && A_r().column_count() == j + 1); auto & last_column = A_r().m_columns[j]; int non_zero_column_cell_index = -1; - for (unsigned k = last_column.cells_size(); k-- > 0;){ + for (unsigned k = last_column.size(); k-- > 0;){ auto & cc = last_column[k]; - if (cc.dead()) continue; if (cc.var() == i) return; non_zero_column_cell_index = k; @@ -1357,20 +1351,15 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { auto & last_row = A_r().m_rows[i]; mpq &cost_j = m_mpq_lar_core_solver.m_r_solver.m_costs[j]; bool cost_is_nz = !is_zero(cost_j); - for (unsigned k = last_row.cells_size(); k-- > 0;) { + for (unsigned k = last_row.size(); k-- > 0;) { auto &rc = last_row[k]; - if (rc.dead()) { - last_row.pop(); - continue; - } if (cost_is_nz) { m_mpq_lar_core_solver.m_r_solver.m_d[rc.var()] += cost_j*rc.get_val(); } - - A_r().remove_element(rc); + A_r().remove_element(last_row, rc); } - lp_assert(last_row.live_size() == 0); - lp_assert(A_r().m_columns[j].live_size() == 0); + lp_assert(last_row.size() == 0); + lp_assert(A_r().m_columns[j].size() == 0); A_r().m_rows.pop_back(); A_r().m_columns.pop_back(); CASSERT("check_static_matrix", A_r().is_correct()); @@ -1379,7 +1368,7 @@ void lar_solver::remove_last_row_and_column_from_tableau(unsigned j) { void lar_solver::remove_last_column_from_A() { // the last column has to be empty - lp_assert(A_r().m_columns.back().live_size() == 0); + lp_assert(A_r().m_columns.back().size() == 0); A_r().m_columns.pop_back(); } diff --git a/src/util/lp/lp_core_solver_base.h b/src/util/lp/lp_core_solver_base.h index 00ba437d1..41b6fe31d 100644 --- a/src/util/lp/lp_core_solver_base.h +++ b/src/util/lp/lp_core_solver_base.h @@ -212,12 +212,10 @@ public: unsigned m = m_A.row_count(); for (unsigned i = 0; i < m; i++) { unsigned bj = m_basis[i]; - lp_assert(m_A.m_columns[bj].live_size() > 0); - if (m_A.m_columns[bj].live_size() > 1) + lp_assert(m_A.m_columns[bj].size() > 0); + if (m_A.m_columns[bj].size() > 1) return true; for (const auto & c : m_A.m_columns[bj]) { - if (c.dead()) - continue; if (m_A.get_val(c) != one_of_type()) return true; else @@ -246,7 +244,6 @@ public: } else { auto d = m_costs[j]; for (const auto & cc : this->m_A.m_columns[j]) { - if (cc.dead()) continue; d -= this->m_costs[this->m_basis[cc.var()]] * this->m_A.get_val(cc); } if (m_d[j] != d) { diff --git a/src/util/lp/lp_core_solver_base_def.h b/src/util/lp/lp_core_solver_base_def.h index 6a9af8a26..c3a0a0a00 100644 --- a/src/util/lp/lp_core_solver_base_def.h +++ b/src/util/lp/lp_core_solver_base_def.h @@ -104,7 +104,6 @@ pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { if (is_zero(a)) return; for (const row_cell & r: m_A.m_rows[i]){ - if (r.dead()) continue; if (r.var() != j) m_d[r.var()] -= a * r.get_val(); } @@ -309,8 +308,7 @@ calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row) { if (numeric_traits::is_zero(pi_1)) { continue; } - for (auto & c : m_A.m_rows[i].m_cells) { - if (c.dead()) continue; + for (auto & c : m_A.m_rows[i]) { unsigned j = c.var(); if (m_basis_heading[j] < 0) { m_pivot_row.add_value_at_index_with_drop_tolerance(j, c.get_val() * pi_1); @@ -591,10 +589,9 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { lp_assert(numeric_traits::precise()); int pivot_index = -1; auto & row = m_A.m_rows[pivot_row]; - unsigned size = row.cells_size(); + unsigned size = row.size(); for (unsigned j = 0; j < size; j++) { auto & c = row[j]; - if (c.dead()) continue; if (c.var() == pivot_col) { pivot_index = static_cast(j); break; @@ -610,7 +607,6 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { this->m_b[pivot_row] /= coeff; for (unsigned j = 0; j < size; j++) { auto & c = row[j]; - if (c.dead()) continue; if (c.var() != pivot_col) { c.coeff() /= coeff; } @@ -621,13 +617,11 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { } template bool lp_core_solver_base:: pivot_column_tableau(unsigned j, unsigned piv_row_index) { - m_A.compress_row_if_needed(piv_row_index); - if (!divide_row_by_pivot(piv_row_index, j)) + if (!divide_row_by_pivot(piv_row_index, j)) return false; auto &column = m_A.m_columns[j]; int pivot_col_cell_index = -1; - for (unsigned k = 0; k < column.cells_size(); k++) { - if (column[k].dead()) continue; + for (unsigned k = 0; k < column.size(); k++) { if (column[k].var() == piv_row_index) { pivot_col_cell_index = k; break; @@ -636,16 +630,18 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { if (pivot_col_cell_index < 0) return false; - if (pivot_col_cell_index != 0) - m_A.swap_with_head_cell(j, pivot_col_cell_index); + if (pivot_col_cell_index != 0) { + lp_assert(column.size() > 1); + // swap the pivot column cell with the head cell + auto c = column[0]; + column[0] = column[pivot_col_cell_index]; + column[pivot_col_cell_index] = c; - CASSERT("check_static_matrix", m_A.is_correct()); - while (column.live_size() > 1) { + m_A.m_rows[piv_row_index][column[0].m_offset].m_offset = 0; + m_A.m_rows[c.var()][c.m_offset].m_offset = pivot_col_cell_index; + } + while (column.size() > 1) { auto & c = column.back(); - if (c.dead()) { - column.pop_last_dead_cell(); - continue; - } lp_assert(c.var() != piv_row_index); if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) { return false; @@ -653,9 +649,6 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) { if (m_pivoted_rows!= nullptr) m_pivoted_rows->insert(c.var()); } - m_A.compress_column_if_needed(j); - lp_assert(column.live_size() == 1); - CASSERT("check_static_matrix", m_A.is_correct()); if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs) pivot_to_reduced_costs_tableau(piv_row_index, j); @@ -769,8 +762,7 @@ fill_reduced_costs_from_m_y_by_rows() { while (i--) { const T & y = m_y[i]; if (is_zero(y)) continue; - for (row_cell & c : m_A.m_rows[i].m_cells) { - if (c.dead()) continue; + for (row_cell & c : m_A.m_rows[i]) { j = c.var(); if (m_basis_heading[j] < 0) { m_d[j] -= y * c.get_val(); @@ -969,8 +961,7 @@ template void lp_core_solver_base::pivot_fixed_v if (get_column_type(basic_j) != column_type::fixed) continue; T a; unsigned j; - for (auto &c : m_A.m_rows[i].m_cells) { - if (c.dead()) continue; + for (auto &c : m_A.m_rows[i]) { j = c.var(); if (j == basic_j) continue; @@ -985,8 +976,7 @@ template void lp_core_solver_base::pivot_fixed_v template bool lp_core_solver_base::remove_from_basis(unsigned basic_j) { indexed_vector w(m_basis.size()); // the buffer unsigned i = m_basis_heading[basic_j]; - for (auto &c : m_A.m_rows[i].m_cells) { - if (c.dead()) continue; + for (auto &c : m_A.m_rows[i]) { if (c.var() == basic_j) continue; if (pivot_column_general(c.var(), basic_j, w)) diff --git a/src/util/lp/lp_primal_core_solver.h b/src/util/lp/lp_primal_core_solver.h index faf9074f6..db92edb05 100644 --- a/src/util/lp/lp_primal_core_solver.h +++ b/src/util/lp/lp_primal_core_solver.h @@ -240,7 +240,6 @@ public: unsigned get_number_of_basic_vars_that_might_become_inf(unsigned j) const { // consider looking at the signs here: todo unsigned r = 0; for (const auto & cc : this->m_A.m_columns[j]) { - if (cc.dead()) continue; unsigned k = this->m_basis[cc.var()]; if (this->m_column_types[k] != column_type::free_column) r++; @@ -254,7 +253,6 @@ public: unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); for (const row_cell& rc : this->m_A.m_rows[i]) { - if (rc.dead()) continue; if (rc.var() == bj) continue; if (bj_needs_to_grow) { @@ -286,9 +284,8 @@ public: unsigned len = 100000000; unsigned bj = this->m_basis[i]; bool bj_needs_to_grow = needs_to_grow(bj); - for (unsigned k = 0; k < this->m_A.m_rows[i].m_cells.size(); k++) { - const row_cell& rc = this->m_A.m_rows[i].m_cells[k]; - if (rc.dead()) continue; + for (unsigned k = 0; k < this->m_A.m_rows[i].size(); k++) { + const row_cell& rc = this->m_A.m_rows[i][k]; unsigned j = rc.var(); if (j == bj) continue; @@ -302,13 +299,13 @@ public: unsigned damage = get_number_of_basic_vars_that_might_become_inf(j); if (damage < num_of_non_free_basics) { num_of_non_free_basics = damage; - len = this->m_A.m_columns[j].live_size(); + len = this->m_A.m_columns[j].size(); choice = k; nchoices = 1; } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].live_size() <= len && (this->m_settings.random_next() % (++nchoices))) { + this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % (++nchoices))) { choice = k; - len = this->m_A.m_columns[j].live_size(); + len = this->m_A.m_columns[j].size(); } } @@ -317,7 +314,7 @@ public: m_inf_row_index_for_tableau = i; return -1; } - const row_cell& rc = this->m_A.m_rows[i].m_cells[choice]; + const row_cell& rc = this->m_A.m_rows[i][choice]; a_ent = rc.coeff(); return rc.var(); } @@ -830,11 +827,11 @@ public: this->m_rows_nz.resize(this->m_A.row_count()); for (unsigned i = 0; i < this->m_A.column_count(); i++) { if (this->m_columns_nz[i] == 0) - this->m_columns_nz[i] = this->m_A.m_columns[i].live_size(); + this->m_columns_nz[i] = this->m_A.m_columns[i].size(); } for (unsigned i = 0; i < this->m_A.row_count(); i++) { if (this->m_rows_nz[i] == 0) - this->m_rows_nz[i] = this->m_A.m_rows[i].live_size(); + this->m_rows_nz[i] = this->m_A.m_rows[i].size(); } } @@ -864,7 +861,7 @@ public: unsigned solve_with_tableau(); bool basis_column_is_set_correctly(unsigned j) const { - return this->m_A.m_columns[j].live_size() == 1; + return this->m_A.m_columns[j].size() == 1; } @@ -884,7 +881,6 @@ public: lp_assert(this->m_basis_heading[j] >= 0); unsigned i = static_cast(this->m_basis_heading[j]); for (const row_cell & rc : this->m_A.m_rows[i]) { - if (rc.dead()) continue; unsigned k = rc.var(); if (k == j) continue; diff --git a/src/util/lp/lp_primal_core_solver_def.h b/src/util/lp/lp_primal_core_solver_def.h index eb4a9ce1d..1e9edbd31 100644 --- a/src/util/lp/lp_primal_core_solver_def.h +++ b/src/util/lp/lp_primal_core_solver_def.h @@ -975,7 +975,7 @@ template void lp_primal_core_solver::delete_fa template void lp_primal_core_solver::init_column_norms() { lp_assert(numeric_traits::precise() == false); for (unsigned j = 0; j < this->m_n(); j++) { - this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].live_size() + 1)) + this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].size() + 1)) + T(static_cast(this->m_settings.random_next() % 10000)) / T(100000); } diff --git a/src/util/lp/lp_primal_core_solver_tableau_def.h b/src/util/lp/lp_primal_core_solver_tableau_def.h index be28bf36f..8f9cf7ff1 100644 --- a/src/util/lp/lp_primal_core_solver_tableau_def.h +++ b/src/util/lp/lp_primal_core_solver_tableau_def.h @@ -266,10 +266,9 @@ template int lp_primal_core_solver::find_leaving_ unsigned row_min_nz = this->m_n() + 1; m_leaving_candidates.clear(); auto & col = this->m_A.m_columns[entering]; - unsigned col_size = col.cells_size(); + unsigned col_size = col.size(); for (;k < col_size && unlimited; k++) { const column_cell & c = col[k]; - if (c.dead()) continue; unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); @@ -277,7 +276,7 @@ template int lp_primal_core_solver::find_leaving_ limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); if (!unlimited) { m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].live_size(); + row_min_nz = this->m_A.m_rows[i].size(); } } if (unlimited) { @@ -289,7 +288,6 @@ template int lp_primal_core_solver::find_leaving_ X ratio; for (;k < col_size; k++) { const column_cell & c = col[k]; - if (c.dead()) continue; unsigned i = c.var(); const T & ed = this->m_A.get_val(c); lp_assert(!numeric_traits::is_zero(ed)); @@ -297,7 +295,7 @@ template int lp_primal_core_solver::find_leaving_ unlimited = true; limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); if (unlimited) continue; - unsigned i_nz = this->m_A.m_rows[i].live_size(); + unsigned i_nz = this->m_A.m_rows[i].size(); if (ratio < t) { t = ratio; m_leaving_candidates.clear(); @@ -306,7 +304,7 @@ template int lp_primal_core_solver::find_leaving_ } else if (ratio == t && i_nz < row_min_nz) { m_leaving_candidates.clear(); m_leaving_candidates.push_back(j); - row_min_nz = this->m_A.m_rows[i].live_size(); + row_min_nz = this->m_A.m_rows[i].size(); } else if (ratio == t && i_nz == row_min_nz) { m_leaving_candidates.push_back(j); } @@ -361,7 +359,6 @@ update_x_tableau(unsigned entering, const X& delta) { this->add_delta_to_x_and_call_tracker(entering, delta); if (!this->m_using_infeas_costs) { for (const auto & c : this->m_A.m_columns[entering]) { - if (c.dead()) continue; unsigned i = c.var(); this->update_x_with_delta_and_track_feasibility(this->m_basis[i], - delta * this->m_A.get_val(c)); } diff --git a/src/util/lp/random_updater_def.h b/src/util/lp/random_updater_def.h index 06cc01163..c972cc175 100644 --- a/src/util/lp/random_updater_def.h +++ b/src/util/lp/random_updater_def.h @@ -83,8 +83,7 @@ void random_updater::add_column_to_sets(unsigned j) { add_value(m_lar_solver.get_core_solver().m_r_x[j]); } else { unsigned row = m_lar_solver.get_core_solver().m_r_heading[j]; - for (auto & row_c : m_lar_solver.get_core_solver().m_r_A.m_rows[row].m_cells) { - if (row_c.dead()) continue; + for (auto & row_c : m_lar_solver.get_core_solver().m_r_A.m_rows[row]) { unsigned cj = row_c.var(); if (m_lar_solver.get_core_solver().m_r_heading[cj] < 0) { m_var_set.insert(cj); diff --git a/src/util/lp/static_matrix.cpp b/src/util/lp/static_matrix.cpp index d0448b6c9..9d12087bb 100644 --- a/src/util/lp/static_matrix.cpp +++ b/src/util/lp/static_matrix.cpp @@ -30,9 +30,6 @@ Revision History: #include "util/lp/lar_solver.h" namespace lp { template void static_matrix::add_columns_at_the_end(unsigned int); -template void static_matrix::add_new_element(unsigned i, unsigned j, const double & v); -template void static_matrix::add_new_element(unsigned i, unsigned j, const mpq & v); -template void static_matrix::add_new_element(unsigned i, unsigned j, const mpq & v); template void static_matrix::clear(); #ifdef Z3DEBUG template bool static_matrix::is_correct() const; @@ -50,6 +47,7 @@ template double static_matrix::get_min_abs_in_row(unsigned int) template void static_matrix::init_empty_matrix(unsigned int, unsigned int); template void static_matrix::init_row_columns(unsigned int, unsigned int); template static_matrix::ref & static_matrix::ref::operator=(double const&); +template void static_matrix::set(unsigned int, unsigned int, double const&); template static_matrix::static_matrix(unsigned int, unsigned int); template void static_matrix::add_column_to_vector(mpq const&, unsigned int, mpq*) const; template void static_matrix::add_columns_at_the_end(unsigned int); @@ -65,6 +63,7 @@ template mpq static_matrix::get_min_abs_in_column(unsigned int) const; template mpq static_matrix::get_min_abs_in_row(unsigned int) const; template void static_matrix::init_row_columns(unsigned int, unsigned int); template static_matrix::ref& static_matrix::ref::operator=(mpq const&); +template void static_matrix::set(unsigned int, unsigned int, mpq const&); template static_matrix::static_matrix(unsigned int, unsigned int); #ifdef Z3DEBUG @@ -73,11 +72,13 @@ template bool static_matrix >::is_correct() const; template void static_matrix >::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; template mpq static_matrix >::get_elem(unsigned int, unsigned int) const; template void static_matrix >::init_empty_matrix(unsigned int, unsigned int); +template void static_matrix >::set(unsigned int, unsigned int, mpq const&); + template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); template bool lp::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); -template void lp::static_matrix >::remove_element(lp::row_cell&); +template void lp::static_matrix >::remove_element(vector, true, unsigned int>&, lp::row_cell&); } diff --git a/src/util/lp/static_matrix.h b/src/util/lp/static_matrix.h index cb6af1379..bb6cdefc8 100644 --- a/src/util/lp/static_matrix.h +++ b/src/util/lp/static_matrix.h @@ -1,22 +1,22 @@ /*++ - Copyright (c) 2017 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation - Module Name: +Module Name: - + - Abstract: +Abstract: - + - Author: +Author: - Lev Nachmanson (levnach) + Lev Nachmanson (levnach) - Revision History: +Revision History: - --*/ +--*/ #pragma once #include "util/vector.h" @@ -29,347 +29,31 @@ #include namespace lp { -class column_cell { - unsigned m_i; // points to the row - unsigned m_offset; // the offset of the element in the matrix row, or the next dead cell in the column_strip -public: - column_cell(unsigned i, unsigned offset) : m_i(i), m_offset(offset) { } - column_cell(unsigned i) : m_i(i) { } - - // index of of the cell row - unsigned var() const { - lp_assert(alive()); - return m_i; - } - unsigned &var() { - return m_i; - } - unsigned offset() const { - lp_assert(alive()); - return m_offset; - } - unsigned & offset() { - lp_assert(alive()); - return m_offset; - } - - unsigned next_dead_index() const { - lp_assert(dead()); - return m_offset; - } - unsigned & next_dead_index() { - return m_offset; - } - - bool alive() const { return !dead(); } - bool dead() const { return m_i == static_cast(-1); } - void set_dead() { m_i = -1;} -}; - template -class row_cell { - unsigned m_j; // points to the column - unsigned m_offset; // offset in column, or the next dead cell in the row_strip - T m_value; -public: +struct row_cell { + unsigned m_j; // points to the column + unsigned m_offset; // offset in column + T m_value; row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_value(val) { } - row_cell(unsigned j, T const & val) : m_j(j), m_value(val) { + row_cell(unsigned j, unsigned offset) : m_j(j), m_offset(offset) { } - - const T & get_val() const { - lp_assert(alive()); - return m_value; - } - T & get_val() { - lp_assert(alive()); - return m_value; - } - void set_val(const T& v) { - lp_assert(alive()); - m_value = v; - } - // index of the cell column - unsigned var() const { - lp_assert(alive()); - return m_j; - } - unsigned &var() { - return m_j; - } - const T & coeff() const { - lp_assert(alive()); - return m_value; - } - T & coeff() { - lp_assert(alive()); - return m_value; - } - // offset in the column vector - unsigned offset() const { - lp_assert(alive()); - return m_offset; - } - unsigned & offset() { - return m_offset; - } - unsigned next_dead_index() const { - lp_assert(dead()); - return m_offset; - } - unsigned & next_dead_index() { - lp_assert(dead()); - return m_offset; - } - bool alive() const { return !dead(); } - bool dead() const { return m_j == static_cast(-1); } - void set_dead() { m_j = static_cast(-1); } + const T & get_val() const { return m_value;} + T & get_val() { return m_value;} + const T & coeff() const { return m_value;} + T & coeff() { return m_value;} + unsigned var() const { return m_j;} + unsigned & var() { return m_j;} + unsigned offset() const { return m_offset;} + unsigned & offset() { return m_offset;} + }; +struct empty_struct {}; +typedef row_cell column_cell; + template -class row_strip { - unsigned m_live_size; - int m_first_dead; -public: - row_strip() : m_live_size(0), m_first_dead(-1) {} - row_cell* begin() { return m_cells.begin();} - const row_cell* begin() const { return m_cells.begin();} - row_cell* end() { return m_cells.end();} - const row_cell* end() const { return m_cells.end();} - unsigned live_size() const { return m_live_size; } - vector> m_cells; - unsigned cells_size() const { return m_cells.size(); } - const row_cell & operator[](unsigned i) const { return m_cells[i]; } - row_cell & operator[](unsigned i) { return m_cells[i];} - - void skip_dead_cell(unsigned k) { - lp_assert(m_cells[k].dead()) - auto * c = &m_cells[m_first_dead]; - for (; c->next_dead_index() != k; c = &m_cells[c->next_dead_index()]); - lp_assert(c->next_dead_index() == k); - c->next_dead_index() = m_cells[k].next_dead_index(); - } - - void pop_last_dead_cell() { - lp_assert(m_cells.back().dead()); - unsigned last = m_cells.size() - 1; - if (m_first_dead == static_cast(last)) - m_first_dead = m_cells.back().next_dead_index(); - else { - skip_dead_cell(last); - } - m_cells.pop_back(); - } - - void pop(){ - bool dead = m_cells.back().dead(); - if (dead) { - pop_last_dead_cell(); - } else { - m_live_size --; - m_cells.pop_back(); - } - } - - bool empty() const { return m_live_size == 0; } - - void delete_at(unsigned j) { - lp_assert(m_cells[j].alive()); - m_live_size--; - if (j == m_cells.size() - 1) - m_cells.pop_back(); - else { - auto & c = m_cells[j]; - c.set_dead(); - c.next_dead_index() = m_first_dead; - m_first_dead = j; - } - CASSERT("check_static_matrix", is_correct()); - } - - bool is_correct() const { - std::set d0; - std::set d1; - unsigned alive = 0; - for (unsigned i = 0; i < m_cells.size(); i++) { - if (m_cells[i].dead()) - d0.insert(i); - else - alive ++; - } - - if ( alive != m_live_size) - return false; - - for (unsigned i = m_first_dead; i != static_cast(-1) ; i = m_cells[i].next_dead_index()) - d1.insert(i); - return d0 == d1; - } - - row_cell & add_cell(unsigned j, const T& val, unsigned & index) { -#ifdef Z3DEBUG - for (const auto & c : m_cells) { - if (c.dead()) continue; - if (c.var() == j) - std::cout << "oops" << std::endl; - } -#endif - if (m_first_dead != -1) { - auto & ret = m_cells[index = m_first_dead]; - m_first_dead = ret.next_dead_index(); - m_live_size++; - ret.var() = j; - ret.coeff() = val; - return ret; - } - lp_assert(m_live_size == m_cells.size()); - index = m_live_size++; - m_cells.push_back(row_cell(j, val)); - return m_cells.back(); - } - - void shrink_to_live() { - m_cells.shrink(live_size()); - m_first_dead = -1; - } -}; - -class column_strip { - vector m_cells; - unsigned m_live_size; - int m_first_dead; -public: - column_strip() : m_live_size(0), m_first_dead(-1) { } - column_cell* begin() { return m_cells.begin();} - const column_cell* begin() const { return m_cells.begin();} - column_cell* end() { return m_cells.end();} - const column_cell* end() const { return m_cells.end();} - unsigned live_size() const { - return m_live_size; - } - - unsigned cells_size() const { - return m_cells.size(); - } - - column_cell& back() { return m_cells.back(); } - void delete_at(unsigned j) { - lp_assert(m_cells[j].alive()); - m_live_size--; - if (j == m_cells.size() - 1) - m_cells.pop_back(); - else { - auto & c = m_cells[j]; - c.set_dead(); - c.next_dead_index() = m_first_dead; - m_first_dead = j; - } - CASSERT("check_static_matrix", is_correct()); - } - - const column_cell& operator[] (unsigned i) const { return m_cells[i];} - column_cell& operator[](unsigned i) { return m_cells[i];} - void pop() { - bool dead = m_cells.back().dead(); - if (dead) { - pop_last_dead_cell(); - } else { - m_live_size --; - m_cells.pop_back(); - } - } - void skip_dead_cell(unsigned k) { - lp_assert(m_cells[k].dead()) - auto * c = &m_cells[m_first_dead]; - for (; c->next_dead_index() != k; c = &m_cells[c->next_dead_index()]); - lp_assert(c->next_dead_index() == k); - c->next_dead_index() = m_cells[k].next_dead_index(); - } - - void pop_last_dead_cell() { - lp_assert(m_cells.back().dead()); - unsigned last = m_cells.size() - 1; - if (m_first_dead == static_cast(last)) - m_first_dead = m_cells.back().next_dead_index(); - else { - skip_dead_cell(last); - } - m_cells.pop_back(); - } - bool is_correct() const { - std::set d0; - std::set d1; - unsigned alive = 0; - for (unsigned i = 0; i < m_cells.size(); i++) { - if (m_cells[i].dead()) - d0.insert(i); - else - alive ++; - } - - if (alive != m_live_size) - return false; - for (unsigned i = m_first_dead; i != static_cast(-1) ; i = m_cells[i].next_dead_index()) - d1.insert(i); - return d0 == d1; - } - - void swap_with_head_cell(unsigned i) { - lp_assert(i > 0); - lp_assert(m_cells[i].alive()); - column_cell head_copy = m_cells[0]; - if (head_copy.dead()) { - if (m_first_dead == 0) { - m_first_dead = i; - } else { - column_cell * c = &m_cells[m_first_dead]; - for (; c->next_dead_index() != 0; c = &m_cells[c->next_dead_index()]); - lp_assert(c->next_dead_index() == 0); - c->next_dead_index() = i; - } - } - m_cells[0] = m_cells[i]; - m_cells[i] = head_copy; - CASSERT("check_static_matrix", is_correct()); - } - - column_cell & add_cell(unsigned i, unsigned & index) { - if (m_first_dead != -1) { - auto & ret = m_cells[index = m_first_dead]; - m_first_dead = ret.next_dead_index(); - m_live_size++; - ret.var() = i; - return ret; - } - lp_assert(m_live_size == m_cells.size()); - index = m_live_size++; - m_cells.push_back(column_cell(i)); - return m_cells.back(); - } - void shrink_to_live() { - m_cells.shrink(live_size()); - m_first_dead = -1; - } -}; - -template -void compress_cells(A& cells, vector& vec_of_cells) { - if (2 * cells.live_size() < cells.cells_size()) - return; - unsigned j = 0; // the available target for copy - for (unsigned i = 0; i < cells.cells_size(); i++) { - auto & c = cells[i]; - if (c.dead()) continue; - if (i == j) { - j++; - continue; - } - vec_of_cells[c.var()][c.offset()].offset() = j; - cells[j++] = c; - } - cells.shrink_to_live(); -} - +using row_strip = vector>; // each assignment for this matrix should be issued only once!!! template @@ -383,13 +67,13 @@ class static_matrix unsigned m_n; dim(unsigned m, unsigned n) :m_m(m), m_n(n) {} }; - // fields - std::stack m_stack; + std::stack m_stack; public: - vector m_vector_of_row_offsets; - indexed_vector m_work_vector; - vector> m_rows; - vector m_columns; + typedef vector column_strip; + vector m_vector_of_row_offsets; + indexed_vector m_work_vector; + vector> m_rows; + vector m_columns; // starting inner classes class ref { static_matrix & m_matrix; @@ -397,9 +81,9 @@ public: unsigned m_col; public: ref(static_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {} - ref & operator=(T const & v) { m_matrix.add_new_element( m_row, m_col, v); return *this; } + ref & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; } - ref operator=(ref & v) { m_matrix.add_new_element(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } + ref operator=(ref & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } operator T () const { return m_matrix.get_elem(m_row, m_col); } }; @@ -415,7 +99,7 @@ public: public: const T & get_val(const column_cell & c) const { - return m_rows[c.var()][c.offset()].get_val(); + return m_rows[c.var()][c.m_offset].get_val(); } column_cell & get_column_cell(const row_cell &rc) { @@ -424,7 +108,7 @@ public: void init_row_columns(unsigned m, unsigned n); - // constructor with no parameters + // constructor with no parameters static_matrix() {} // constructor @@ -459,11 +143,11 @@ public: void remove_last_column(unsigned j); - void remove_element(row_cell & elem_to_remove); + void remove_element(vector> & row, row_cell & elem_to_remove); void multiply_column(unsigned column, T const & alpha) { for (auto & t : m_columns[column]) { - auto & r = m_rows[t.var()].m_cells[t.offset()]; + auto & r = m_rows[t.var()][t.offset()]; r.coeff() *= alpha; } } @@ -482,6 +166,8 @@ public: return column_cell(column, offset); } + void set(unsigned row, unsigned col, T const & val); + ref operator()(unsigned row, unsigned col) { return ref(*this, row, col); } std::set> get_domain(); @@ -490,8 +176,8 @@ public: T get_max_abs_in_row(unsigned row) const; void add_column_to_vector (const T & a, unsigned j, T * v) const { - for (const auto & c : m_columns[j]) { - v[c.var()] += a * get_val(c); + for (const auto & it : m_columns[j]) { + v[it.var()] += a * get_val(it); } } @@ -504,6 +190,9 @@ public: void check_consistency(); #endif + + void cross_out_row(unsigned k); + // void fix_row_indices_in_each_column_for_crossed_row(unsigned k); @@ -514,9 +203,9 @@ public: T get_elem(unsigned i, unsigned j) const; - unsigned number_of_non_zeroes_in_column(unsigned j) const { return m_columns[j].live_size(); } + unsigned number_of_non_zeroes_in_column(unsigned j) const { return m_columns[j].size(); } - unsigned number_of_non_zeroes_in_row(unsigned i) const { return m_rows[i].live_size(); } + unsigned number_of_non_zeroes_in_row(unsigned i) const { return m_rows[i].size(); } unsigned number_of_non_zeroes() const { unsigned ret = 0; @@ -549,12 +238,12 @@ public: m_stack.push(d); } - void pop_row_columns(const row_strip & row) { + void pop_row_columns(const vector> & row) { for (auto & c : row) { - if (c.dead()) { - continue; - } - m_columns[c.var()].delete_at(c.offset()); + unsigned j = c.m_j; + auto & col = m_columns[j]; + lp_assert(col[col.size() - 1].var() == m_rows.size() -1 ); // todo : start here!!!! + col.pop_back(); } } @@ -580,13 +269,12 @@ public: m_columns.pop_back(); // delete the last column m_stack.pop(); } - CASSERT("check_static_matrix", is_correct()); + lp_assert(is_correct()); } void multiply_row(unsigned row, T const & alpha) { - for (auto & t : m_rows[row].m_cells) { - if (t.alive()) - t.coeff() *= alpha; + for (auto & t : m_rows[row]) { + t.m_value *= alpha; } } @@ -599,8 +287,8 @@ public: T dot_product_with_column(const vector & y, unsigned j) const { lp_assert(j < column_count()); T ret = numeric_traits::zero(); - for (auto & c : m_columns[j]) { - ret += y[c.var()] * get_val(c); + for (auto & it : m_columns[j]) { + ret += y[it.var()] * get_val(it); // get_value_of_column_cell(it); } return ret; } @@ -614,20 +302,18 @@ public: m_rows[i] = m_rows[ii]; m_rows[ii] = t; // now fix the columns - for (const auto & rc : m_rows[i]) { - if (rc.dead()) continue; - column_cell & cc = m_columns[rc.var()][rc.offset()]; + for (auto & rc : m_rows[i]) { + column_cell & cc = m_columns[rc.m_j][rc.m_offset]; lp_assert(cc.var() == ii); cc.var() = i; } - for (const auto & rc : m_rows[ii]) { - if (rc.dead()) continue; - column_cell & cc = m_columns[rc.var()][rc.offset()]; + for (auto & rc : m_rows[ii]) { + column_cell & cc = m_columns[rc.m_j][rc.m_offset]; lp_assert(cc.var() == i); cc.var() = ii; } + } - void fill_last_row_with_pivoting_loop_block(unsigned j, const vector & basis_heading) { int row_index = basis_heading[j]; if (row_index < 0) @@ -637,18 +323,17 @@ public: return; for (const auto & c : m_rows[row_index]) { - if (c.dead()) continue; - if (c.var() == j) { + if (c.m_j == j) { continue; } - T & wv = m_work_vector.m_data[c.var()]; + T & wv = m_work_vector.m_data[c.m_j]; bool was_zero = is_zero(wv); - wv -= alpha * c.coeff(); + wv -= alpha * c.m_value; if (was_zero) - m_work_vector.m_index.push_back(c.var()); + m_work_vector.m_index.push_back(c.m_j); else { if (is_zero(wv)) { - m_work_vector.erase_from_index(c.var()); + m_work_vector.erase_from_index(c.m_j); } } } @@ -666,7 +351,7 @@ public: lp_assert(row_count() > 0); m_work_vector.resize(column_count()); T a; - // we use the form -it + 1 = 0 + // we use the form -it + 1 = 0 m_work_vector.set_value(one_of_type(), bj); for (auto p : row) { m_work_vector.set_value(-p.coeff(), p.var()); @@ -682,10 +367,10 @@ public: unsigned last_row = row_count() - 1; for (unsigned j : m_work_vector.m_index) { - add_new_element(last_row, j, m_work_vector.m_data[j]); + set (last_row, j, m_work_vector.m_data[j]); } lp_assert(column_count() > 0); - add_new_element(last_row, column_count() - 1, one_of_type()); + set(last_row, column_count() - 1, one_of_type()); } void copy_column_to_vector (unsigned j, vector & v) const { @@ -702,8 +387,7 @@ public: L ret = zero_of_type(); lp_assert(row < m_rows.size()); for (auto & it : m_rows[row]) { - if (it.dead()) continue; - ret += w[it.var()] * it.coeff(); + ret += w[it.m_j] * it.get_val(); } return ret; } @@ -715,8 +399,8 @@ public: column_cell_plus(const column_cell & c, const static_matrix& A) : m_c(c), m_A(A) {} unsigned var() const { return m_c.var(); } - const T & coeff() const { return m_A.m_rows[var()][m_c.offset()].get_val(); } - bool dead() const { return m_c.dead(); } + const T & coeff() const { return m_A.m_rows[var()][m_c.m_offset].get_val(); } + }; struct column_container { @@ -728,7 +412,7 @@ public: // fields const column_cell *m_c; const static_matrix& m_A; - const column_cell *m_end; + //typedefs @@ -742,19 +426,13 @@ public: reference operator*() const { return column_cell_plus(*m_c, m_A); } - self_type operator++() { self_type i = *this; - m_c++; - return i; - } - - self_type operator++(int) { - m_c++; - return *this; - } + self_type operator++() { self_type i = *this; m_c++; return i; } + self_type operator++(int) { m_c++; return *this; } const_iterator(const column_cell* it, const static_matrix& A) : m_c(it), - m_A(A){} + m_A(A) + {} bool operator==(const self_type &other) const { return m_c == other.m_c; } @@ -772,30 +450,8 @@ public: column_container column(unsigned j) const { return column_container(j, *this); - } - void swap_with_head_cell(unsigned j, unsigned offset) { - column_strip & col = m_columns[j]; - column_cell & head = col[0]; - column_cell & cc = col[offset]; - if (head.alive()) { - m_rows[head.var()][head.offset()].offset() = offset; - } - lp_assert(cc.alive()); - m_rows[cc.var()][cc.offset()].offset() = 0; - col.swap_with_head_cell(offset); - } - - - void compress_row_if_needed(unsigned i) { - compress_cells(m_rows[i], m_columns); - } - - void compress_column_if_needed(unsigned j) { - compress_cells(m_columns[j], m_rows); - } - ref_row operator[](unsigned i) const { return ref_row(*this, i);} typedef T coefftype; typedef X argtype; diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index 43c91cefa..1dcaa34f8 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -36,10 +36,8 @@ void static_matrix::init_row_columns(unsigned m, unsigned n) { template void static_matrix::scan_row_ii_to_offset_vector(const row_strip & rvals) { - for (unsigned j = 0; j < rvals.cells_size(); j++) { - if (rvals[j].dead()) continue; - m_vector_of_row_offsets[rvals[j].var()] = j; - } + for (unsigned j = 0; j < rvals.size(); j++) + m_vector_of_row_offsets[rvals[j].var()] = j; } @@ -48,39 +46,33 @@ template bool static_matrix::pivot_row_to_row_giv lp_assert(i < row_count() && ii < column_count() && i != ii); T alpha = -get_val(c); lp_assert(!is_zero(alpha)); - compress_row_if_needed(ii); auto & rowii = m_rows[ii]; - remove_element(rowii[c.offset()]); + remove_element(rowii, rowii[c.m_offset]); scan_row_ii_to_offset_vector(rowii); - unsigned prev_size_ii = rowii.cells_size(); + unsigned prev_size_ii = rowii.size(); // run over the pivot row and update row ii - for (const auto & iv : m_rows[i].m_cells) { - if (iv.dead()) continue; + for (const auto & iv : m_rows[i]) { unsigned j = iv.var(); if (j == pivot_col) continue; - lp_assert(!is_zero(iv.coeff())); - T alv = alpha * iv.coeff(); + T alv = alpha * iv.m_value; + lp_assert(!is_zero(iv.m_value)); int j_offs = m_vector_of_row_offsets[j]; if (j_offs == -1) { // it is a new element add_new_element(ii, j, alv); } else { - rowii[j_offs].coeff() += alv; + rowii[j_offs].m_value += alv; } } // clean the work vector for (unsigned k = 0; k < prev_size_ii; k++) { - auto & c = rowii[k]; - if (c.dead()) continue; - m_vector_of_row_offsets[c.var()] = -1; + m_vector_of_row_offsets[rowii[k].var()] = -1; } + // remove zeroes - for (unsigned k = rowii.cells_size(); k-- > 0; ) { - auto & c = rowii[k]; - if (c.dead()) - continue; - if (is_zero(c.coeff())) - remove_element(c); + for (unsigned k = rowii.size(); k-- > 0; ) { + if (is_zero(rowii[k].m_value)) + remove_element(rowii, rowii[k]); } return !rowii.empty(); } @@ -115,12 +107,12 @@ template void static_matrix::init_empty_matrix init_row_columns(m, n); } -template unsigned static_matrix::lowest_row_in_column(unsigned col) { +template unsigned static_matrix::lowest_row_in_column(unsigned col) { + lp_assert(col < column_count()); column_strip & colstrip = m_columns[col]; - lp_assert(colstrip.live_size() > 0); + lp_assert(colstrip.size() > 0); unsigned ret = 0; - for (const auto & t : colstrip) { - if (t.dead()) continue; + for (auto & t : colstrip) { if (t.var() > ret) { ret = t.var(); } @@ -147,7 +139,7 @@ template void static_matrix::remove_last_column(u auto & row = m_rows[it.var()]; unsigned offset = row.size() - 1; for (auto row_it = row.rbegin(); row_it != row.rend(); row_it ++) { - if (row_it->var() == j) { + if (row_it-.var() == j) { row.erase(row.begin() + offset); break; } @@ -158,6 +150,18 @@ template void static_matrix::remove_last_column(u m_vector_of_row_offsets.pop_back(); } + + + +template void static_matrix::set(unsigned row, unsigned col, T const & val) { + if (numeric_traits::is_zero(val)) return; + lp_assert(row < row_count() && col < column_count()); + auto & r = m_rows[row]; + unsigned offs_in_cols = static_cast(m_columns[col].size()); + m_columns[col].push_back(make_column_cell(row, static_cast(r.size()))); + r.push_back(make_row_cell(col, offs_in_cols, val)); +} + template std::set> static_matrix::get_domain() { std::set> ret; @@ -262,9 +266,50 @@ template void static_matrix::check_consistency } #endif + +template void static_matrix::cross_out_row(unsigned k) { +#ifdef Z3DEBUG + check_consistency(); +#endif + cross_out_row_from_columns(k, m_rows[k]); + fix_row_indices_in_each_column_for_crossed_row(k); + m_rows.erase(m_rows.begin() + k); +#ifdef Z3DEBUG + regen_domain(); + check_consistency(); +#endif +} + + +template void static_matrix::fix_row_indices_in_each_column_for_crossed_row(unsigned k) { + for (unsigned j = 0; j < m_columns.size(); j++) { + auto & col = m_columns[j]; + for (int i = 0; i < col.size(); i++) { + if (col[i].var() > k) { + col[i].var()--; + } + } + } +} + +template void static_matrix::cross_out_row_from_columns(unsigned k, row_strip & row) { + for (auto & t : row) { + cross_out_row_from_column(t.var(), k); + } +} + +template void static_matrix::cross_out_row_from_column(unsigned col, unsigned k) { + auto & s = m_columns[col]; + for (unsigned i = 0; i < s.size(); i++) { + if (s[i].var() == k) { + s.erase(s.begin() + i); + break; + } + } +} + template T static_matrix::get_elem(unsigned i, unsigned j) const { // should not be used in efficient code !!!! for (auto & t : m_rows[i]) { - if (t.dead()) continue; if (t.var() == j) { return t.get_val(); } @@ -297,22 +342,16 @@ template bool static_matrix::is_correct() const { auto &r = m_rows[i]; std::unordered_set s; for (auto & rc : r) { - if (rc.dead()) continue; if (s.find(rc.var()) != s.end()) { return false; } s.insert(rc.var()); if (rc.var() >= m_columns.size()) return false; - const auto& col = m_columns[rc.var()]; - if (col.cells_size() <= rc.offset()) + if (rc.m_offset >= m_columns[rc.var()].size()) return false; - const auto &cc = col[rc.offset()]; - if (cc.dead()) + if (rc.get_val() != get_val(m_columns[rc.var()][rc.m_offset])) return false; - if (& m_rows[cc.var()][cc.offset()] != & rc) { - return false; - } if (is_zero(rc.get_val())) { return false; } @@ -324,56 +363,51 @@ template bool static_matrix::is_correct() const { auto & c = m_columns[j]; std::unordered_set s; for (auto & cc : c) { - if (cc.dead()) - continue; if (s.find(cc.var()) != s.end()) { return false; } s.insert(cc.var()); if (cc.var() >= m_rows.size()) return false; - auto & rc = m_rows[cc.var()][cc.offset()]; - if (rc.dead()) + if (cc.m_offset >= m_rows[cc.var()].size()) return false; - if (&cc != &m_columns[rc.var()][rc.offset()]) + if (get_val(cc) != m_rows[cc.var()][cc.m_offset].get_val()) return false; } } - for (auto & row: m_rows) { - if (! row.is_correct()) - return false; - } - for (auto & col: m_columns) { - if (! col.is_correct()) - return false; - } + return true; } template -void static_matrix::remove_element(row_cell & rc) { - lp_assert(rc.alive()); - unsigned j = rc.var(); - unsigned j_offset = rc.offset(); - auto & col = m_columns[j]; - column_cell & c = col[j_offset]; - unsigned i = c.var(); - unsigned i_offset = c.offset(); - col.delete_at(j_offset); - m_rows[i].delete_at(i_offset); -} +void static_matrix::remove_element(vector> & row_vals, row_cell & row_el_iv) { + unsigned column_offset = row_el_iv.m_offset; + auto & column_vals = m_columns[row_el_iv.var()]; + column_cell& cs = m_columns[row_el_iv.var()][column_offset]; + unsigned row_offset = cs.m_offset; + if (column_offset != column_vals.size() - 1) { + auto & cc = column_vals[column_offset] = column_vals.back(); // copy from the tail + m_rows[cc.var()][cc.offset()].offset() = column_offset; + } + + if (row_offset != row_vals.size() - 1) { + auto & rc = row_vals[row_offset] = row_vals.back(); // copy from the tail + m_columns[rc.var()][rc.offset()].offset() = row_offset; + } + column_vals.pop_back(); + row_vals.pop_back(); +} template -void static_matrix::add_new_element(unsigned i, unsigned j, const T& val) { - auto & row = m_rows[i]; - auto & col = m_columns[j]; - unsigned offset_in_row, offset_in_col; - row_cell& rc = row.add_cell(j, val, offset_in_row); - column_cell& cc = col.add_cell(i, offset_in_col); - rc.offset() = offset_in_col; - cc.offset() = offset_in_row; +void static_matrix::add_new_element(unsigned row, unsigned col, const T& val) { + auto & row_vals = m_rows[row]; + auto & col_vals = m_columns[col]; + unsigned row_el_offs = static_cast(row_vals.size()); + unsigned col_el_offs = static_cast(col_vals.size()); + row_vals.push_back(row_cell(col, col_el_offs, val)); + col_vals.push_back(column_cell(row, row_el_offs)); } } From 7370396c3052d06cb8e47f4eb062ea6cca9bd53b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 1 Aug 2018 08:06:56 -0700 Subject: [PATCH 102/118] fix the build Signed-off-by: Lev Nachmanson --- src/util/lp/static_matrix_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/static_matrix_def.h b/src/util/lp/static_matrix_def.h index 1dcaa34f8..7949573de 100644 --- a/src/util/lp/static_matrix_def.h +++ b/src/util/lp/static_matrix_def.h @@ -139,7 +139,7 @@ template void static_matrix::remove_last_column(u auto & row = m_rows[it.var()]; unsigned offset = row.size() - 1; for (auto row_it = row.rbegin(); row_it != row.rend(); row_it ++) { - if (row_it-.var() == j) { + if (row_it.var() == j) { row.erase(row.begin() + offset); break; } From 77d68409c29102c53e550c6bb72779ddb59fa531 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Aug 2018 08:43:32 -0700 Subject: [PATCH 103/118] handle null declarations for kind Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/smt/theory_bv.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 4f4da6bd4..52be66e77 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -895,7 +895,7 @@ extern "C" { RESET_ERROR_CODE(); func_decl* _d = to_func_decl(d); - if (null_family_id == _d->get_family_id()) { + if (d == nullptr || null_family_id == _d->get_family_id()) { return Z3_OP_UNINTERPRETED; } if (mk_c(c)->get_basic_fid() == _d->get_family_id()) { diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index e693c4531..a9b3e6131 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -850,6 +850,7 @@ namespace smt { } bool theory_bv::internalize_term(app * term) { + try { SASSERT(term->get_family_id() == get_family_id()); TRACE("bv", tout << "internalizing term: " << mk_bounded_pp(term, get_manager()) << "\n";); if (approximate_term(term)) { @@ -907,6 +908,11 @@ namespace smt { UNREACHABLE(); return false; } + } + catch (z3_exception& ex) { + IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); + throw; + } } #define MK_NO_OVFL(NAME, OP) \ From 075cf106aae7285df7b89cfdfcf3549d487648bf Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 1 Aug 2018 08:46:03 -0700 Subject: [PATCH 104/118] fix the build Signed-off-by: Lev Nachmanson --- src/util/lp/lar_solver.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/lp/lar_solver.cpp b/src/util/lp/lar_solver.cpp index 78bd45e94..654eb7017 100644 --- a/src/util/lp/lar_solver.cpp +++ b/src/util/lp/lar_solver.cpp @@ -870,10 +870,10 @@ void lar_solver::fill_last_row_of_A_r(static_matrix> & A, for (auto & t : ls->m_coeffs) { lp_assert(!is_zero(t.second)); var_index j = t.first; - A.add_new_element(last_row, j, - t.second); + A.set(last_row, j, - t.second); } unsigned basis_j = A.column_count() - 1; - A.add_new_element(last_row, basis_j, mpq(1)); + A.set(last_row, basis_j, mpq(1)); } template @@ -895,7 +895,7 @@ void lar_solver::copy_from_mpq_matrix(static_matrix & matr) { matr.m_columns.resize(A_r().column_count()); for (unsigned i = 0; i < matr.row_count(); i++) { for (auto & it : A_r().m_rows[i]) { - matr.add_new_element(i, it.var(), convert_struct::convert(it.get_val())); + matr.set(i, it.var(), convert_struct::convert(it.get_val())); } } } @@ -1840,11 +1840,11 @@ void lar_solver::fill_last_row_of_A_d(static_matrix & A, const l for (auto & t : ls->m_coeffs) { lp_assert(!is_zero(t.second)); var_index j = t.first; - A.add_new_element(last_row, j, -t.second.get_double()); + A.set(last_row, j, -t.second.get_double()); } unsigned basis_j = A.column_count() - 1; - A.add_new_element(last_row, basis_j, -1); + A.set(last_row, basis_j, -1); lp_assert(A.is_correct()); } From adfbc2d0012b7ff8538eea2599ee3a05be28b4b7 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 1 Aug 2018 10:26:39 -0700 Subject: [PATCH 105/118] fix the build Signed-off-by: Lev Nachmanson --- src/test/lp/lp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 37a096827..6e418fe68 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2541,7 +2541,7 @@ void read_row_cols(unsigned i, static_matrix& A, std::ifstream & lp_assert(r.size() == 4); unsigned j = atoi(r[1].c_str()); double v = atof(r[3].c_str()); - A.add_new_element(i, j, v); + A.set(i, j, v); } while (true); } From 8b08821112c9307341f4711a9d4a1df9bf998b35 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 Aug 2018 17:31:14 -0700 Subject: [PATCH 106/118] fix #1784, fix #1783 Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.h | 26 +++++++++++++++++++------- src/smt/theory_lra.cpp | 5 ++++- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 17602efcf..fc98c97e7 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -134,13 +134,25 @@ namespace datatype { ~plus() override { m_arg1->dec_ref(); m_arg2->dec_ref(); } size* subst(obj_map& S) override { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } sort_size eval(obj_map const& S) override { - sort_size s1 = m_arg1->eval(S); - sort_size s2 = m_arg2->eval(S); - if (s1.is_infinite()) return s1; - if (s2.is_infinite()) return s2; - if (s1.is_very_big()) return s1; - if (s2.is_very_big()) return s2; - rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); + rational r(0); + ptr_vector todo; + todo.push_back(m_arg1); + todo.push_back(m_arg2); + while (!todo.empty()) { + size* s = todo.back(); + todo.pop_back(); + plus* p = dynamic_cast(s); + if (p) { + todo.push_back(p->m_arg1); + todo.push_back(p->m_arg2); + } + else { + sort_size sz = s->eval(S); + if (sz.is_infinite()) return sz; + if (sz.is_very_big()) return sz; + r += rational(sz.size(), rational::ui64()); + } + } return sort_size(r); } }; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index a49e0e4bb..267412da6 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2805,7 +2805,9 @@ public: TRACE("arith", display(tout << st << " v" << v << "\n");); switch (st) { case lp::lp_status::OPTIMAL: { - inf_rational val(term_max.x, term_max.y); + init_variable_values(); + inf_rational val = get_value(v); + // inf_rational val(term_max.x, term_max.y); blocker = mk_gt(v); return inf_eps(rational::zero(), val); } @@ -2851,6 +2853,7 @@ public: } theory_var add_objective(app* term) { + TRACE("opt", tout << expr_ref(term, m) << "\n";); return internalize_def(term); } From fed977b492aa98d672a50abe8e5cca404bd214d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Aug 2018 10:08:16 -0700 Subject: [PATCH 107/118] fix #1782 Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 6 +++--- src/api/z3_logger.h | 1 + src/api/z3_replayer.cpp | 8 ++++++-- src/ast/ast.cpp | 1 + src/sat/ba_solver.cpp | 1 + src/sat/sat_solver.cpp | 13 ++++++++----- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 22c0dea99..375a855de 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -311,7 +311,7 @@ def display_args_to_z3(params): core_py.write("a%s" % i) i = i + 1 -NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc', 'Z3_mk_interpolation_context' ] +NULLWrapped = [ 'Z3_mk_context', 'Z3_mk_context_rc' ] Unwrapped = [ 'Z3_del_context', 'Z3_get_error_code' ] def mk_py_wrappers(): @@ -955,9 +955,9 @@ def def_API(name, result, params): log_c.write(" Au(a%s);\n" % sz) exe_c.write("in.get_uint_array(%s)" % i) elif ty == INT: - log_c.write("U(a%s[i]);" % i) + log_c.write("I(a%s[i]);" % i) log_c.write(" }\n") - log_c.write(" Au(a%s);\n" % sz) + log_c.write(" Ai(a%s);\n" % sz) exe_c.write("in.get_int_array(%s)" % i) elif ty == BOOL: log_c.write("U(a%s[i]);" % i) diff --git a/src/api/z3_logger.h b/src/api/z3_logger.h index 211601713..8f0eb5371 100644 --- a/src/api/z3_logger.h +++ b/src/api/z3_logger.h @@ -42,6 +42,7 @@ static void __declspec(noinline) Sy(Z3_symbol sym) { } static void __declspec(noinline) Ap(unsigned sz) { *g_z3_log << "p " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) Au(unsigned sz) { *g_z3_log << "u " << sz << "\n"; g_z3_log->flush(); } +static void __declspec(noinline) Ai(unsigned sz) { *g_z3_log << "i " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) Asy(unsigned sz) { *g_z3_log << "s " << sz << "\n"; g_z3_log->flush(); } static void __declspec(noinline) C(unsigned id) { *g_z3_log << "C " << id << "\n"; g_z3_log->flush(); } void __declspec(noinline) _Z3_append_log(char const * msg) { *g_z3_log << "M \"" << ll_escaped(msg) << "\"\n"; g_z3_log->flush(); } diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 0e8297879..8ebac8068 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -78,6 +78,7 @@ struct z3_replayer::imp { std::stringstream strm; strm << "expecting " << kind2string(k) << " at position " << pos << " but got " << kind2string(m_args[pos].m_kind); + TRACE("z3_replayer", tout << strm.str() << "\n";); throw z3_replayer_exception(strm.str().c_str()); } } @@ -186,10 +187,10 @@ struct z3_replayer::imp { sz++; } else { - throw z3_replayer_exception("invalid scaped character"); + throw z3_replayer_exception("invalid escaped character"); } if (val > 255) - throw z3_replayer_exception("invalid scaped character"); + throw z3_replayer_exception("invalid escaped character"); next(); } TRACE("z3_replayer_escape", tout << "val: " << val << "\n";); @@ -497,6 +498,7 @@ struct z3_replayer::imp { case 'p': case 's': case 'u': + case 'i': // push array next(); skip_blank(); read_uint64(); TRACE("z3_replayer", tout << "[" << m_line << "] " << "A " << m_uint64 << "\n";); @@ -504,6 +506,8 @@ struct z3_replayer::imp { push_array(static_cast(m_uint64), OBJECT); else if (c == 's') push_array(static_cast(m_uint64), SYMBOL); + else if (c == 'i') + push_array(static_cast(m_uint64), INT64); else push_array(static_cast(m_uint64), UINT64); break; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5a14a64c0..11a15492c 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1403,6 +1403,7 @@ void ast_manager::init() { inc_ref(m_false); } + template static void mark_array_ref(ast_mark& mark, unsigned sz, T * const * a) { for(unsigned i = 0; i < sz; i++) { diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 38cd07fa7..4226b9791 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1976,6 +1976,7 @@ namespace sat { for (unsigned i = 0; !found && i < c.k(); ++i) { found = c[i] == l; } + CTRACE("ba",!found, s().display(tout << l << ":" << c << "\n");); SASSERT(found);); // IF_VERBOSE(0, if (_debug_conflict) verbose_stream() << "ante " << l << " " << c << "\n"); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 04a0274c4..7ddc80813 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1552,12 +1552,15 @@ namespace sat { void solver::reinit_assumptions() { if (tracking_assumptions() && at_base_lvl() && !inconsistent()) { TRACE("sat", tout << m_assumptions << "\n";); + if (!propagate(false)) return; push(); - for (unsigned i = 0; !inconsistent() && i < m_user_scope_literals.size(); ++i) { - assign(~m_user_scope_literals[i], justification()); + for (literal lit : m_user_scope_literals) { + if (inconsistent()) break; + assign(~lit, justification()); } - for (unsigned i = 0; !inconsistent() && i < m_assumptions.size(); ++i) { - assign(m_assumptions[i], justification()); + for (literal lit : m_assumptions) { + if (inconsistent()) break; + assign(lit, justification()); } TRACE("sat", for (literal a : m_assumptions) { @@ -2934,7 +2937,7 @@ namespace sat { break; } case justification::EXT_JUSTIFICATION: { - fill_ext_antecedents(m_lemma[i], js); + fill_ext_antecedents(~m_lemma[i], js); for (literal l : m_ext_antecedents) { update_lrb_reasoned(l); } From 7bd4a313dd7cdffa7d9369f7a555f5d07b9ac269 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Aug 2018 10:41:07 -0700 Subject: [PATCH 108/118] expr utilities for pb Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Expr.cs | 44 ++++++++++++++++++++++++++++++++++++++++++ src/sat/ba_solver.cpp | 1 + 2 files changed, 45 insertions(+) diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 849d1af79..99baaa8e4 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -89,6 +89,15 @@ namespace Microsoft.Z3 } } + /// + /// The i'th argument of the expression. + /// + public Expr Arg(uint i) + { + Contract.Ensures(Contract.Result() != null); + return Expr.Create(Context, Native.Z3_get_app_arg(Context.nCtx, NativeObject, i)); + } + /// /// Update the arguments of the expression using the arguments /// The number of new arguments should coincide with the current number of arguments. @@ -315,6 +324,41 @@ namespace Microsoft.Z3 /// public bool IsImplies { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_IMPLIES; } } + /// + /// Indicates whether the term is at-most + /// + public bool IsAtMost { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_AT_MOST; } } + + /// + /// Retrieve bound of at-most + /// + public uint AtMostBound { get { Contract.Requires(IsAtMost); return (uint)FuncDecl.Parameters[0].Int; } } + + /// + /// Indicates whether the term is at-least + /// + public bool IsAtLeast { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_AT_LEAST; } } + + /// + /// Retrieve bound of at-least + /// + public uint AtLeastBound { get { Contract.Requires(IsAtLeast); return (uint)FuncDecl.Parameters[0].Int; } } + + /// + /// Indicates whether the term is pbeq + /// + public bool IsPbEq { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_EQ; } } + + /// + /// Indicates whether the term is pble + /// + public bool IsPbLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_LE; } } + + /// + /// Indicates whether the term is pbge + /// + public bool IsPbGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PB_GE; } } + #endregion #region Arithmetic Terms diff --git a/src/sat/ba_solver.cpp b/src/sat/ba_solver.cpp index 38cd07fa7..94d27a0c9 100644 --- a/src/sat/ba_solver.cpp +++ b/src/sat/ba_solver.cpp @@ -1976,6 +1976,7 @@ namespace sat { for (unsigned i = 0; !found && i < c.k(); ++i) { found = c[i] == l; } + CTRACE("ba",!found, tout << l << ": " << c << "\n";); SASSERT(found);); // IF_VERBOSE(0, if (_debug_conflict) verbose_stream() << "ante " << l << " " << c << "\n"); From f306f75e362be2ae1544e80e2d9b4ca6892b37d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 2 Aug 2018 20:18:27 -0700 Subject: [PATCH 109/118] harness internalization and API for #1776 Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 6 ++++-- src/api/api_model.cpp | 12 ++++++------ src/smt/smt_model_generator.cpp | 3 +-- src/smt/theory_bv.cpp | 3 ++- src/util/rlimit.h | 4 +++- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 673d0b1c9..cc2a13aed 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -379,11 +379,13 @@ extern "C" { Z3_TRY; LOG_Z3_dec_ref(c, a); RESET_ERROR_CODE(); - if (to_ast(a)->get_ref_count() == 0) { + if (a && to_ast(a)->get_ref_count() == 0) { SET_ERROR_CODE(Z3_DEC_REF_ERROR, nullptr); return; } - mk_c(c)->m().dec_ref(to_ast(a)); + if (a) { + mk_c(c)->m().dec_ref(to_ast(a)); + } Z3_CATCH; } diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index e9dd3580b..939cccdca 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -206,9 +206,8 @@ extern "C" { ptr_vector const & universe = to_model_ref(m)->get_universe(to_sort(s)); Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); mk_c(c)->save_object(v); - unsigned sz = universe.size(); - for (unsigned i = 0; i < sz; i++) { - v->m_ast_vector.push_back(universe[i]); + for (expr * e : universe) { + v->m_ast_vector.push_back(e); } RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(nullptr); @@ -230,7 +229,7 @@ extern "C" { Z3_TRY; LOG_Z3_is_as_array(c, a); RESET_ERROR_CODE(); - return is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY); + return a && is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY); Z3_CATCH_RETURN(Z3_FALSE); } @@ -238,7 +237,7 @@ extern "C" { Z3_TRY; LOG_Z3_get_as_array_func_decl(c, a); RESET_ERROR_CODE(); - if (is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY)) { + if (a && is_expr(to_ast(a)) && is_app_of(to_expr(a), mk_c(c)->get_array_fid(), OP_AS_ARRAY)) { RETURN_Z3(of_func_decl(to_func_decl(to_app(a)->get_decl()->get_parameter(0).get_ast()))); } else { @@ -252,6 +251,7 @@ extern "C" { Z3_TRY; LOG_Z3_add_func_interp(c, m, f, else_val); RESET_ERROR_CODE(); + CHECK_NON_NULL(f, nullptr); func_decl* d = to_func_decl(f); model* mdl = to_model_ref(m); Z3_func_interp_ref * f_ref = alloc(Z3_func_interp_ref, *mk_c(c), mdl); @@ -268,7 +268,7 @@ extern "C" { LOG_Z3_add_const_interp(c, m, f, a); RESET_ERROR_CODE(); func_decl* d = to_func_decl(f); - if (d->get_arity() != 0) { + if (!d || d->get_arity() != 0) { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); } else { diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 190f7f79e..a4b3029e2 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -438,8 +438,7 @@ namespace smt { } } - extra_fresh_value * model_generator::mk_extra_fresh_value(sort * s) { - SASSERT(s->is_infinite()); + extra_fresh_value * model_generator::mk_extra_fresh_value(sort * s) { extra_fresh_value * r = alloc(extra_fresh_value, s, m_fresh_idx); m_fresh_idx++; m_extra_fresh_values.push_back(r); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index a9b3e6131..33207d15a 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -850,6 +850,7 @@ namespace smt { } bool theory_bv::internalize_term(app * term) { + scoped_suspend_rlimit _suspend_cancel(get_manager().limit()); try { SASSERT(term->get_family_id() == get_family_id()); TRACE("bv", tout << "internalizing term: " << mk_bounded_pp(term, get_manager()) << "\n";); @@ -910,7 +911,7 @@ namespace smt { } } catch (z3_exception& ex) { - IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); + IF_VERBOSE(1, verbose_stream() << "internalize_term: " << ex.msg() << "\n";); throw; } } diff --git a/src/util/rlimit.h b/src/util/rlimit.h index 60d26be7f..cc022a963 100644 --- a/src/util/rlimit.h +++ b/src/util/rlimit.h @@ -65,12 +65,14 @@ public: class scoped_suspend_rlimit { reslimit & m_limit; + bool m_suspend; public: scoped_suspend_rlimit(reslimit& r): m_limit(r) { + m_suspend = r.m_suspend; r.m_suspend = true; } ~scoped_suspend_rlimit() { - m_limit.m_suspend = false; + m_limit.m_suspend = m_suspend; } }; From c247abfc65ac33fdf4ffc3b95dc62eac1cd19e4a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 3 Aug 2018 22:13:25 -0700 Subject: [PATCH 110/118] prepare js output Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 1 + scripts/mk_util.py | 49 ++++++++++++++++++++++++++++++++-- scripts/update_api.py | 62 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index dada93069..05ca765e9 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -89,6 +89,7 @@ def init_project_def(): set_z3py_dir('api/python') add_python(_libz3Component) add_python_install(_libz3Component) + add_js() # Examples add_cpp_example('cpp_example', 'c++') add_cpp_example('z3_tptp', 'tptp') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index d51735255..770e118ee 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -82,6 +82,7 @@ VS_ARM = False LINUX_X64 = True ONLY_MAKEFILES = False Z3PY_SRC_DIR=None +Z3JS_SRC_DIR=None VS_PROJ = False TRACE = False PYTHON_ENABLED=False @@ -89,6 +90,7 @@ DOTNET_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 @@ -654,6 +656,7 @@ def display_help(exit_code): print(" --dotnet-key= sign the .NET assembly using the private key in .") print(" --java generate Java bindings.") print(" --ml generate OCaml bindings.") + print(" --js generate JScript bindings.") print(" --python generate Python bindings.") print(" --staticlib build Z3 static library.") print(" --staticbin build a statically linked Z3 binary.") @@ -687,14 +690,14 @@ 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_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 DOTNET_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 LINUX_X64, SLOW_OPTIMIZE, USE_OMP, LOG_SYNC global GUARD_CF, ALWAYS_DYNAMIC_BASE try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', ['build=', 'debug', 'silent', 'x64', 'help', 'makefiles', 'showcpp', 'vsproj', 'guardcf', - 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', + 'trace', 'dotnet', 'dotnet-key=', 'staticlib', 'prefix=', 'gmp', 'java', 'parallel=', 'gprof', 'js', 'githash=', 'git-describe', 'x86', 'ml', 'optimize', 'noomp', 'pypkgdir=', 'python', 'staticbin', 'log-sync']) except: print("ERROR: Invalid command line option") @@ -755,6 +758,8 @@ def parse_options(): GIT_DESCRIBE = True elif opt in ('', '--ml'): ML_ENABLED = True + elif opt == "--js": + JS_ENABLED = True elif opt in ('', '--noomp'): USE_OMP = False elif opt in ('', '--log-sync'): @@ -817,6 +822,16 @@ 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) @@ -852,6 +867,10 @@ 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(): return VERBOSE @@ -862,6 +881,9 @@ def is_java_enabled(): def is_ml_enabled(): return ML_ENABLED +def is_js_enabled(): + return JS_ENABLED + def is_dotnet_enabled(): return DOTNET_ENABLED @@ -1411,6 +1433,22 @@ class DLLComponent(Component): shutil.copy('%s.a' % os.path.join(build_path, self.dll_name), '%s.a' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) +class JsComponent(Component): + def __init__(self): + Component.__init__(self, "js", None, []) + + def main_component(self): + return False + + def mk_win_dist(self, build_path, dist_path): + return + + def mk_unix_dist(self, build_path, dist_path): + return + + def mk_makefile(self, out): + return + class PythonComponent(Component): def __init__(self, name, libz3Component): assert isinstance(libz3Component, DLLComponent) @@ -2320,6 +2358,9 @@ def add_python(libz3Component): name = 'python' reg_component(name, PythonComponent(name, libz3Component)) +def add_js(): + reg_component('js', JsComponent()) + def add_python_install(libz3Component): name = 'python_install' reg_component(name, PythonInstallComponent(name, libz3Component)) @@ -2949,6 +2990,9 @@ 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.generate_files(api_files=new_api_files, api_output_dir=get_component('api').src_dir, @@ -2956,6 +3000,7 @@ def mk_bindings(api_files): 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 375a855de..917df94a2 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -741,6 +741,59 @@ def mk_java(java_dir, package_name): if mk_util.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' } + +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' } + +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 @@ -1742,6 +1795,7 @@ 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): """ @@ -1822,6 +1876,9 @@ 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) parser = argparse.ArgumentParser(description=__doc__) @@ -1855,6 +1912,10 @@ 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: @@ -1878,6 +1939,7 @@ 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 e041ebbe809c40fee9f53387be1c5a808077f539 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 10:00:49 -0700 Subject: [PATCH 111/118] bmc improvements, move fd_solver to self-contained directory Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 7 +- src/CMakeLists.txt | 1 + src/muz/base/dl_rule.cpp | 20 +++- src/muz/base/dl_rule.h | 16 +++ src/muz/base/dl_rule_set.cpp | 8 ++ src/muz/base/dl_rule_set.h | 1 + src/muz/base/fp_params.pyg | 3 +- src/muz/bmc/dl_bmc_engine.cpp | 105 +++++++++--------- src/muz/bmc/dl_bmc_engine.h | 7 +- src/muz/fp/dl_cmds.cpp | 5 +- .../bounded_int2bv_solver.cpp | 3 +- .../bounded_int2bv_solver.h | 0 .../enum2bv_solver.cpp | 2 +- .../{portfolio => fd_solver}/enum2bv_solver.h | 0 .../{portfolio => fd_solver}/fd_solver.cpp | 2 +- .../{portfolio => fd_solver}/fd_solver.h | 0 .../{portfolio => fd_solver}/pb2bv_solver.cpp | 6 +- .../{portfolio => fd_solver}/pb2bv_solver.h | 0 src/tactic/portfolio/CMakeLists.txt | 6 +- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 2 +- 21 files changed, 120 insertions(+), 76 deletions(-) rename src/tactic/{portfolio => fd_solver}/bounded_int2bv_solver.cpp (99%) rename src/tactic/{portfolio => fd_solver}/bounded_int2bv_solver.h (100%) rename src/tactic/{portfolio => fd_solver}/enum2bv_solver.cpp (99%) rename src/tactic/{portfolio => fd_solver}/enum2bv_solver.h (100%) rename src/tactic/{portfolio => fd_solver}/fd_solver.cpp (96%) rename src/tactic/{portfolio => fd_solver}/fd_solver.h (100%) rename src/tactic/{portfolio => fd_solver}/pb2bv_solver.cpp (99%) rename src/tactic/{portfolio => fd_solver}/pb2bv_solver.h (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 05ca765e9..ca62f5c5f 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -54,6 +54,8 @@ def init_project_def(): add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') add_lib('qe', ['smt','sat','nlsat','tactic','nlsat_tactic'], 'qe') + add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') + add_lib('fd_solver', ['core_tactics', 'arith_tactics', 'sat_solver'], 'tactic/fd_solver') add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') add_lib('dataflow', ['muz'], 'muz/dataflow') add_lib('transforms', ['muz', 'hilbert', 'dataflow'], 'muz/transforms') @@ -61,14 +63,13 @@ def init_project_def(): add_lib('spacer', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/spacer') add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') - add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') + add_lib('bmc', ['muz', 'transforms', 'fd_solver'], 'muz/bmc') add_lib('fp', ['muz', 'clp', 'tab', 'rel', 'bmc', 'ddnf', 'spacer'], 'muz/fp') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') - add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') add_lib('smtlogic_tactics', ['ackermannization', 'sat_solver', 'arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') - add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') + add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'fd_solver', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_fpa.h', 'z3_spacer.h'] add_lib('api', ['portfolio', 'realclosure', 'opt'], diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7dee4039a..826f87e8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -91,6 +91,7 @@ add_subdirectory(tactic/ufbv) add_subdirectory(sat/sat_solver) add_subdirectory(tactic/smtlogics) add_subdirectory(tactic/fpa) +add_subdirectory(tactic/fd_solver) add_subdirectory(tactic/portfolio) add_subdirectory(opt) add_subdirectory(api) diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index d709209e1..0dbeba5b3 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -57,7 +57,8 @@ namespace datalog { m_hnf(m), m_qe(m, params_ref(), false), m_rwr(m), - m_ufproc(m) {} + m_ufproc(m), + m_fd_proc(m) {} void rule_manager::inc_ref(rule * r) { if (r) { @@ -928,6 +929,23 @@ namespace datalog { return exist || univ; } + bool rule_manager::is_finite_domain(rule const& r) const { + m_visited.reset(); + m_fd_proc.reset(); + for (unsigned i = r.get_uninterpreted_tail_size(); i < r.get_tail_size(); ++i) { + for_each_expr_core(m_fd_proc, m_visited, r.get_tail(i)); + } + for (unsigned i = 0; i < r.get_uninterpreted_tail_size(); ++i) { + for (expr* arg : *r.get_tail(i)) { + for_each_expr_core(m_fd_proc, m_visited, arg); + } + } + for (expr* arg : *r.get_head()) { + for_each_expr_core(m_fd_proc, m_visited, arg); + } + return m_fd_proc.is_fd(); + } + bool rule::has_negation() const { for (unsigned i = 0; i < get_uninterpreted_tail_size(); ++i) { if (is_neg_tail(i)) { diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 102427a4a..7e85199cf 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -92,6 +92,20 @@ namespace datalog { void reset() { m_exist = m_univ = false; } }; + struct fd_finder_proc { + ast_manager& m; + bv_util m_bv; + bool m_is_fd; + fd_finder_proc(ast_manager& m): m(m), m_bv(m), m_is_fd(true) {} + + bool is_fd() const { return m_is_fd; } + bool is_fd(sort* s) { return m.is_bool(s) || m_bv.is_bv_sort(s); } + void operator()(var* n) { m_is_fd &= is_fd(n->get_sort()); } + void operator()(quantifier* ) { m_is_fd = false; } + void operator()(app* n) { m_is_fd &= is_fd(n->get_decl()->get_range()); } + void reset() { m_is_fd = true; } + }; + /** \brief Manager for the \c rule class @@ -117,6 +131,7 @@ namespace datalog { mutable uninterpreted_function_finder_proc m_ufproc; mutable quantifier_finder_proc m_qproc; mutable expr_sparse_mark m_visited; + mutable fd_finder_proc m_fd_proc; // only the context can create a rule_manager @@ -265,6 +280,7 @@ namespace datalog { bool has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const; void has_quantifiers(rule const& r, bool& existential, bool& universal) const; bool has_quantifiers(rule const& r) const; + bool is_finite_domain(rule const& r) const; }; diff --git a/src/muz/base/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp index 28abbba41..5114fdca4 100644 --- a/src/muz/base/dl_rule_set.cpp +++ b/src/muz/base/dl_rule_set.cpp @@ -501,6 +501,14 @@ namespace datalog { } } + bool rule_set::is_finite_domain() const { + for (rule * r : *this) { + if (!get_rule_manager().is_finite_domain(*r)) + return false; + } + return true; + } + void rule_set::display_deps( std::ostream & out ) const { diff --git a/src/muz/base/dl_rule_set.h b/src/muz/base/dl_rule_set.h index 748574d96..736dd8888 100644 --- a/src/muz/base/dl_rule_set.h +++ b/src/muz/base/dl_rule_set.h @@ -253,6 +253,7 @@ namespace datalog { const func_decl_set & get_output_predicates() const { return m_output_preds; } func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); } + bool is_finite_domain() const; void display(std::ostream & out) const; diff --git a/src/muz/base/fp_params.pyg b/src/muz/base/fp_params.pyg index ee842d28e..dea7ad328 100644 --- a/src/muz/base/fp_params.pyg +++ b/src/muz/base/fp_params.pyg @@ -1,8 +1,7 @@ def_module_params('fp', description='fixedpoint parameters', export=True, - params=(('timeout', UINT, UINT_MAX, 'set timeout'), - ('engine', SYMBOL, 'auto-config', + params=(('engine', SYMBOL, 'auto-config', 'Select: auto-config, datalog, bmc, spacer'), ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 5f69e4c37..e8cf8ff9d 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -17,22 +17,22 @@ Revision History: --*/ +#include "ast/datatype_decl_plugin.h" +#include "ast/dl_decl_plugin.h" +#include "ast/ast_smt_pp.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/scoped_proof.h" +#include "smt/smt_solver.h" +#include "tactic/portfolio/fd_solver.h" #include "muz/base/dl_context.h" #include "muz/base/dl_rule_transformer.h" #include "muz/bmc/dl_bmc_engine.h" #include "muz/transforms/dl_mk_slice.h" -#include "smt/smt_kernel.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/dl_decl_plugin.h" -#include "ast/rewriter/bool_rewriter.h" #include "model/model_smt2_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/well_sorted.h" -#include "ast/rewriter/rewriter_def.h" #include "muz/transforms/dl_transforms.h" #include "muz/transforms/dl_mk_rule_inliner.h" -#include "ast/scoped_proof.h" - #include "muz/base/fp_params.hpp" namespace datalog { @@ -53,7 +53,7 @@ namespace datalog { m_bit_width = 4; lbool res = l_false; while (res == l_false) { - b.m_solver.push(); + b.m_solver->push(); IF_VERBOSE(1, verbose_stream() << "bit_width: " << m_bit_width << "\n";); compile(); b.checkpoint(); @@ -61,12 +61,12 @@ namespace datalog { expr* T = m.mk_const(symbol("T"), mk_index_sort()); expr_ref fml(m.mk_app(q, T), m); b.assert_expr(fml); - res = b.m_solver.check(); + res = b.m_solver->check_sat(0, nullptr); if (res == l_true) { res = get_model(); } - b.m_solver.pop(1); + b.m_solver->pop(1); ++m_bit_width; } return res; @@ -141,10 +141,10 @@ namespace datalog { } void setup() { - b.m_fparams.m_relevancy_lvl = 2; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = true; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + p.set_bool("smt.mbqi", true); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -252,7 +252,7 @@ namespace datalog { rational num; unsigned level, bv_size; - b.m_solver.get_model(md); + b.m_solver->get_model(md); func_decl* pred = b.m_query_pred; dl_decl_util util(m); T = m.mk_const(symbol("T"), mk_index_sort()); @@ -468,10 +468,9 @@ namespace datalog { } void setup() { - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - // b.m_fparams.m_mbqi = true; - b.m_fparams.m_relevancy_lvl = 2; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -482,7 +481,7 @@ namespace datalog { q_at_level = m.mk_implies(q, p); b.assert_expr(q_at_level); expr* qr = q.get(); - return b.m_solver.check(1, &qr); + return b.m_solver->check_sat(1, &qr); } proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) { @@ -548,7 +547,7 @@ namespace datalog { scoped_proof _sp(m); expr_ref level_query = compile_query(b.m_query_pred, level); model_ref md; - b.m_solver.get_model(md); + b.m_solver->get_model(md); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); proof_ref pr(m); pr = get_proof(md, b.m_query_pred, to_app(level_query), level); @@ -755,11 +754,10 @@ namespace datalog { m_pred2sort.reset(); m_pinned.reset(); m_sort2pred.reset(); - b.m_fparams.m_relevancy_lvl = 0; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = false; - b.m_fparams.m_relevancy_lvl = 2; + params_ref p; + p.set_uint("smt.relevancy", 2ul); + p.set_bool("smt.mbqi", false); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -1096,12 +1094,12 @@ namespace datalog { fml = m.mk_app(q, trace.get(), path.get()); b.assert_expr(fml); while (true) { - lbool is_sat = b.m_solver.check(); + lbool is_sat = b.m_solver->check_sat(0, nullptr); model_ref md; if (is_sat == l_false) { return is_sat; } - b.m_solver.get_model(md); + b.m_solver->get_model(md); mk_answer(md, trace, path); return l_true; } @@ -1111,13 +1109,13 @@ namespace datalog { expr_ref trace_val(m), eq(m); trace_val = (*md)(trace); eq = m.mk_eq(trace, trace_val); - b.m_solver.push(); - b.m_solver.assert_expr(eq); - lbool is_sat = b.m_solver.check(); + b.m_solver->push(); + b.m_solver->assert_expr(eq); + lbool is_sat = b.m_solver->check_sat(0, nullptr); if (is_sat != l_false) { - b.m_solver.get_model(md); + b.m_solver->get_model(md); } - b.m_solver.pop(1); + b.m_solver->pop(1); if (is_sat == l_false) { IF_VERBOSE(1, verbose_stream() << "infeasible trace " << mk_pp(trace_val, m) << "\n";); eq = m.mk_not(eq); @@ -1131,8 +1129,8 @@ namespace datalog { trace = (*md)(trace); path = (*md)(path); IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n"; - for (unsigned i = 0; i < b.m_solver.size(); ++i) { - verbose_stream() << mk_pp(b.m_solver.get_formula(i), m) << "\n"; + for (unsigned i = 0; i < b.m_solver->get_num_assertions(); ++i) { + verbose_stream() << mk_pp(b.m_solver->get_assertion(i), m) << "\n"; }); scoped_proof _sp(m); proof_ref pr(m); @@ -1183,7 +1181,7 @@ namespace datalog { model_ref md; proof_ref pr(m); rule_unifier unifier(b.m_ctx); - b.m_solver.get_model(md); + b.m_solver->get_model(md); func_decl* pred = b.m_query_pred; SASSERT(m.is_true(md->get_const_interp(to_app(level_query)->get_decl()))); @@ -1283,11 +1281,10 @@ namespace datalog { void setup() { - b.m_fparams.m_relevancy_lvl = 0; - b.m_fparams.m_model = true; - b.m_fparams.m_model_compact = true; - b.m_fparams.m_mbqi = false; - // m_fparams.m_auto_config = false; + params_ref p; + p.set_uint("smt.relevancy", 0ul); + p.set_bool("smt.mbqi", false); + b.m_solver->updt_params(p); b.m_rule_trace.reset(); } @@ -1295,7 +1292,7 @@ namespace datalog { lbool check(unsigned level) { expr_ref level_query = mk_level_predicate(b.m_query_pred, level); expr* q = level_query.get(); - return b.m_solver.check(1, &q); + return b.m_solver->check_sat(1, &q); } expr_ref mk_level_predicate(func_decl* p, unsigned level) { @@ -1428,7 +1425,7 @@ namespace datalog { engine_base(ctx.get_manager(), "bmc"), m_ctx(ctx), m(ctx.get_manager()), - m_solver(m, m_fparams), + m_solver(nullptr), m_rules(ctx), m_query_pred(m), m_answer(m), @@ -1438,7 +1435,7 @@ namespace datalog { bmc::~bmc() {} lbool bmc::query(expr* query) { - m_solver.reset(); + m_solver = nullptr; m_answer = nullptr; m_ctx.ensure_opened(); m_rules.reset(); @@ -1471,6 +1468,7 @@ namespace datalog { IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); + params_ref p; if (m_rules.get_num_rules() == 0) { return l_false; } @@ -1478,18 +1476,25 @@ namespace datalog { return l_false; } - if (is_linear()) { if (m_ctx.get_engine() == QBMC_ENGINE) { + m_solver = mk_smt_solver(m, p, symbol::null); qlinear ql(*this); return ql.check(); } else { + if (m_rules.is_finite_domain()) { + m_solver = mk_fd_solver(m, p); + } + else { + m_solver = mk_smt_solver(m, p, symbol::null); + } linear lin(*this); return lin.check(); } } else { + m_solver = mk_smt_solver(m, p, symbol::null); IF_VERBOSE(0, verbose_stream() << "WARNING: non-linear BMC is highly inefficient\n";); nonlinear nl(*this); return nl.check(); @@ -1498,7 +1503,7 @@ namespace datalog { void bmc::assert_expr(expr* e) { TRACE("bmc", tout << mk_pp(e, m) << "\n";); - m_solver.assert_expr(e); + m_solver->assert_expr(e); } bool bmc::is_linear() const { @@ -1525,11 +1530,11 @@ namespace datalog { } void bmc::collect_statistics(statistics& st) const { - m_solver.collect_statistics(st); + m_solver->collect_statistics(st); } void bmc::reset_statistics() { - m_solver.reset_statistics(); + // m_solver->reset_statistics(); } expr_ref bmc::get_answer() { diff --git a/src/muz/bmc/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h index a5824fa82..9a7424287 100644 --- a/src/muz/bmc/dl_bmc_engine.h +++ b/src/muz/bmc/dl_bmc_engine.h @@ -22,10 +22,8 @@ Revision History: #include "util/params.h" #include "util/statistics.h" -#include "smt/smt_kernel.h" #include "ast/bv_decl_plugin.h" -#include "smt/params/smt_params.h" - +#include "solver/solver.h" namespace datalog { class context; @@ -33,8 +31,7 @@ namespace datalog { class bmc : public engine_base { context& m_ctx; ast_manager& m; - smt_params m_fparams; - smt::kernel m_solver; + solver_ref m_solver; rule_set m_rules; func_decl_ref m_query_pred; expr_ref m_answer; diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 4605826ba..6fa4b39c4 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -245,7 +245,8 @@ public: datalog::context& dlctx = m_dl_ctx->dlctx(); set_background(ctx); dlctx.updt_params(m_params); - unsigned timeout = m_dl_ctx->get_params().timeout(); + unsigned timeout = ctx.params().m_timeout; + unsigned rlimit = ctx.params().rlimit(); cancel_eh eh(ctx.m().limit()); bool query_exn = false; lbool status = l_undef; @@ -253,12 +254,14 @@ public: IF_VERBOSE(10, verbose_stream() << "(query)\n";); scoped_ctrl_c ctrlc(eh); scoped_timer timer(timeout, &eh); + scoped_rlimit _rlimit(ctx.m().limit(), rlimit); cmd_context::scoped_watch sw(ctx); try { status = dlctx.rel_query(1, &m_target); } catch (z3_error & ex) { ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; + print_statistics(ctx); throw ex; } catch (z3_exception& ex) { diff --git a/src/tactic/portfolio/bounded_int2bv_solver.cpp b/src/tactic/fd_solver/bounded_int2bv_solver.cpp similarity index 99% rename from src/tactic/portfolio/bounded_int2bv_solver.cpp rename to src/tactic/fd_solver/bounded_int2bv_solver.cpp index 6389ed739..8791a6282 100644 --- a/src/tactic/portfolio/bounded_int2bv_solver.cpp +++ b/src/tactic/fd_solver/bounded_int2bv_solver.cpp @@ -16,8 +16,7 @@ Author: Notes: --*/ - -#include "tactic/portfolio/bounded_int2bv_solver.h" +#include "tactic/fd_solver/bounded_int2bv_solver.h" #include "solver/solver_na2as.h" #include "tactic/tactic.h" #include "ast/rewriter/pb2bv_rewriter.h" diff --git a/src/tactic/portfolio/bounded_int2bv_solver.h b/src/tactic/fd_solver/bounded_int2bv_solver.h similarity index 100% rename from src/tactic/portfolio/bounded_int2bv_solver.h rename to src/tactic/fd_solver/bounded_int2bv_solver.h diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/fd_solver/enum2bv_solver.cpp similarity index 99% rename from src/tactic/portfolio/enum2bv_solver.cpp rename to src/tactic/fd_solver/enum2bv_solver.cpp index 29c6aeb39..a864d9631 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/fd_solver/enum2bv_solver.cpp @@ -26,9 +26,9 @@ Notes: #include "model/model_smt2_pp.h" #include "tactic/tactic.h" #include "tactic/generic_model_converter.h" -#include "tactic/portfolio/enum2bv_solver.h" #include "solver/solver_na2as.h" #include "ast/rewriter/enum2bv_rewriter.h" +#include "tactic/fd_solver/enum2bv_solver.h" class enum2bv_solver : public solver_na2as { ast_manager& m; diff --git a/src/tactic/portfolio/enum2bv_solver.h b/src/tactic/fd_solver/enum2bv_solver.h similarity index 100% rename from src/tactic/portfolio/enum2bv_solver.h rename to src/tactic/fd_solver/enum2bv_solver.h diff --git a/src/tactic/portfolio/fd_solver.cpp b/src/tactic/fd_solver/fd_solver.cpp similarity index 96% rename from src/tactic/portfolio/fd_solver.cpp rename to src/tactic/fd_solver/fd_solver.cpp index b0d95baee..acb579214 100644 --- a/src/tactic/portfolio/fd_solver.cpp +++ b/src/tactic/fd_solver/fd_solver.cpp @@ -17,7 +17,7 @@ Notes: --*/ -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "tactic/tactic.h" #include "sat/sat_solver/inc_sat_solver.h" #include "tactic/portfolio/enum2bv_solver.h" diff --git a/src/tactic/portfolio/fd_solver.h b/src/tactic/fd_solver/fd_solver.h similarity index 100% rename from src/tactic/portfolio/fd_solver.h rename to src/tactic/fd_solver/fd_solver.h diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp similarity index 99% rename from src/tactic/portfolio/pb2bv_solver.cpp rename to src/tactic/fd_solver/pb2bv_solver.cpp index 60ca6a5dc..83396408e 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -17,13 +17,13 @@ Notes: --*/ #include "ast/ast_pp.h" +#include "ast/rewriter/pb2bv_rewriter.h" +#include "ast/rewriter/th_rewriter.h" #include "model/model_smt2_pp.h" -#include "tactic/portfolio/pb2bv_solver.h" #include "tactic/tactic.h" #include "tactic/generic_model_converter.h" #include "solver/solver_na2as.h" -#include "ast/rewriter/pb2bv_rewriter.h" -#include "ast/rewriter/th_rewriter.h" +#include "tactic/fd_solver/pb2bv_solver.h" class pb2bv_solver : public solver_na2as { ast_manager& m; diff --git a/src/tactic/portfolio/pb2bv_solver.h b/src/tactic/fd_solver/pb2bv_solver.h similarity index 100% rename from src/tactic/portfolio/pb2bv_solver.h rename to src/tactic/fd_solver/pb2bv_solver.h diff --git a/src/tactic/portfolio/CMakeLists.txt b/src/tactic/portfolio/CMakeLists.txt index 2b714cc2c..0913bf7f0 100644 --- a/src/tactic/portfolio/CMakeLists.txt +++ b/src/tactic/portfolio/CMakeLists.txt @@ -1,10 +1,6 @@ z3_add_component(portfolio SOURCES - bounded_int2bv_solver.cpp default_tactic.cpp - enum2bv_solver.cpp - fd_solver.cpp - pb2bv_solver.cpp smt_strategic_solver.cpp solver2lookahead.cpp COMPONENT_DEPENDENCIES @@ -17,7 +13,7 @@ z3_add_component(portfolio smtlogic_tactics subpaving_tactic ufbv_tactic + fd_solver TACTIC_HEADERS default_tactic.h - fd_solver.h ) diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 7f71114f4..3e479524e 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -31,7 +31,7 @@ Notes: #include "tactic/fpa/qffplra_tactic.h" #include "tactic/smtlogics/qfaufbv_tactic.h" #include "tactic/smtlogics/qfauflia_tactic.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index b8ba2f59d..6718eb13f 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -33,7 +33,7 @@ Notes: #include "tactic/smtlogics/qfidl_tactic.h" #include "tactic/smtlogics/nra_tactic.h" #include "tactic/portfolio/default_tactic.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "tactic/ufbv/ufbv_tactic.h" #include "tactic/fpa/qffp_tactic.h" #include "muz/fp/horn_tactic.h" From d47e06732c71934eb64b7ad6e5b37b7354561169 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 10:02:15 -0700 Subject: [PATCH 112/118] bmc improvements, move fd_solver to self-contained directory Signed-off-by: Nikolaj Bjorner --- src/muz/bmc/dl_bmc_engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index e8cf8ff9d..f804a239a 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -25,7 +25,7 @@ Revision History: #include "ast/rewriter/rewriter_def.h" #include "ast/scoped_proof.h" #include "smt/smt_solver.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "muz/base/dl_context.h" #include "muz/base/dl_rule_transformer.h" #include "muz/bmc/dl_bmc_engine.h" From 74efe253a0e3688af73392a4661f3a67ec7d0a5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 10:09:23 -0700 Subject: [PATCH 113/118] fix header files Signed-off-by: Nikolaj Bjorner --- src/tactic/fd_solver/fd_solver.cpp | 6 +++--- src/tactic/fd_solver/pb2bv_solver.cpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tactic/fd_solver/fd_solver.cpp b/src/tactic/fd_solver/fd_solver.cpp index acb579214..2af30b089 100644 --- a/src/tactic/fd_solver/fd_solver.cpp +++ b/src/tactic/fd_solver/fd_solver.cpp @@ -20,9 +20,9 @@ Notes: #include "tactic/fd_solver/fd_solver.h" #include "tactic/tactic.h" #include "sat/sat_solver/inc_sat_solver.h" -#include "tactic/portfolio/enum2bv_solver.h" -#include "tactic/portfolio/pb2bv_solver.h" -#include "tactic/portfolio/bounded_int2bv_solver.h" +#include "tactic/fd_solver/enum2bv_solver.h" +#include "tactic/fd_solver/pb2bv_solver.h" +#include "tactic/fd_solver/bounded_int2bv_solver.h" #include "solver/solver2tactic.h" #include "solver/parallel_tactic.h" #include "solver/parallel_params.hpp" diff --git a/src/tactic/fd_solver/pb2bv_solver.cpp b/src/tactic/fd_solver/pb2bv_solver.cpp index 83396408e..fd4fb8e73 100644 --- a/src/tactic/fd_solver/pb2bv_solver.cpp +++ b/src/tactic/fd_solver/pb2bv_solver.cpp @@ -16,6 +16,7 @@ Notes: --*/ +#include "util/statistics.h" #include "ast/ast_pp.h" #include "ast/rewriter/pb2bv_rewriter.h" #include "ast/rewriter/th_rewriter.h" From 6400da63ab1977647116829f2e6e8f298be4bb63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 10:10:52 -0700 Subject: [PATCH 114/118] missing file Signed-off-by: Nikolaj Bjorner --- src/tactic/fd_solver/CMakeLists.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/tactic/fd_solver/CMakeLists.txt diff --git a/src/tactic/fd_solver/CMakeLists.txt b/src/tactic/fd_solver/CMakeLists.txt new file mode 100644 index 000000000..2a2254543 --- /dev/null +++ b/src/tactic/fd_solver/CMakeLists.txt @@ -0,0 +1,19 @@ +z3_add_component(fd_solver + SOURCES + bounded_int2bv_solver.cpp + enum2bv_solver.cpp + fd_solver.cpp + pb2bv_solver.cpp + COMPONENT_DEPENDENCIES + aig_tactic + fp + fpa_tactics + qe + sat_solver + sls_tactic + smtlogic_tactics + subpaving_tactic + ufbv_tactic + TACTIC_HEADERS + fd_solver.h +) From 60110bb289af53293e483b381ae2c6ff28c48fb4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 10:34:13 -0700 Subject: [PATCH 115/118] reduce dependencies in CMakeLists file Signed-off-by: Nikolaj Bjorner --- src/tactic/fd_solver/CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/tactic/fd_solver/CMakeLists.txt b/src/tactic/fd_solver/CMakeLists.txt index 2a2254543..67567d19d 100644 --- a/src/tactic/fd_solver/CMakeLists.txt +++ b/src/tactic/fd_solver/CMakeLists.txt @@ -5,15 +5,7 @@ z3_add_component(fd_solver fd_solver.cpp pb2bv_solver.cpp COMPONENT_DEPENDENCIES - aig_tactic - fp - fpa_tactics - qe sat_solver - sls_tactic - smtlogic_tactics - subpaving_tactic - ufbv_tactic TACTIC_HEADERS fd_solver.h ) From a3c692c05fa571eaae06e604b9acf2e990df2042 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 5 Aug 2018 13:49:26 -0700 Subject: [PATCH 116/118] fix include paths Signed-off-by: Nikolaj Bjorner --- src/test/get_consequences.cpp | 2 +- src/test/pb2bv.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 767b07b6d..0e5124d58 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -11,7 +11,7 @@ Copyright (c) 2016 Microsoft Corporation #include "tactic/bv/dt2bv_tactic.h" #include "tactic/tactic.h" #include "model/model_smt2_pp.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" static expr_ref mk_const(ast_manager& m, char const* name, sort* s) { return expr_ref(m.mk_const(symbol(name), s), m); diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index d58bf61ee..493d81bb7 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -16,7 +16,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast_util.h" #include "ast/pb_decl_plugin.h" #include "ast/rewriter/th_rewriter.h" -#include "tactic/portfolio/fd_solver.h" +#include "tactic/fd_solver/fd_solver.h" #include "solver/solver.h" static void test1() { From 84c7df75d6b7d0594e834158a9ad460554014065 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Aug 2018 16:21:27 -0700 Subject: [PATCH 117/118] record statistics setting in config_params so that fp engine can access them, fix serialization bug when check-assumptions returns unsat Signed-off-by: Nikolaj Bjorner --- src/cmd_context/context_params.cpp | 7 +++++++ src/cmd_context/context_params.h | 1 + src/muz/base/bind_variables.cpp | 2 +- src/muz/base/fp_params.pyg | 2 +- src/muz/fp/dl_cmds.cpp | 2 +- src/muz/spacer/spacer_context.cpp | 4 ++-- src/sat/sat_solver/inc_sat_solver.cpp | 28 ++++++++++++++++++++------- src/sat/tactic/goal2sat.cpp | 2 +- src/shell/main.cpp | 1 + 9 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index dc3880674..c0ab1e3e2 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -37,6 +37,7 @@ context_params::context_params() { m_model_compress = true; m_timeout = UINT_MAX; m_rlimit = 0; + m_statistics = false; updt_params(); } @@ -109,6 +110,9 @@ void context_params::set(char const * param, char const * value) { else if (p == "dump_models") { set_bool(m_dump_models, param, value); } + else if (p == "stats") { + set_bool(m_statistics, param, value); + } else if (p == "trace") { set_bool(m_trace, param, value); } @@ -158,6 +162,7 @@ void context_params::updt_params(params_ref const & p) { m_unsat_core = p.get_bool("unsat_core", m_unsat_core); m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count); m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant); + m_statistics = p.get_bool("stats", m_statistics); } void context_params::collect_param_descrs(param_descrs & d) { @@ -174,6 +179,8 @@ void context_params::collect_param_descrs(param_descrs & d) { d.insert("dot_proof_file", CPK_STRING, "file in which to output graphical proofs", "proof.dot"); d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false"); d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false"); + d.insert("stats", CPK_BOOL, "enable/disable statistics", "false"); + // statistics are hidden as they are controlled by the /st option. collect_solver_param_descrs(d); } diff --git a/src/cmd_context/context_params.h b/src/cmd_context/context_params.h index 8ca36dfc9..f00d39641 100644 --- a/src/cmd_context/context_params.h +++ b/src/cmd_context/context_params.h @@ -45,6 +45,7 @@ public: bool m_unsat_core; bool m_smtlib2_compliant; // it must be here because it enable/disable the use of coercions in the ast_manager. unsigned m_timeout; + bool m_statistics; unsigned rlimit() const { return m_rlimit; } context_params(); diff --git a/src/muz/base/bind_variables.cpp b/src/muz/base/bind_variables.cpp index cbafc57b0..1e918b172 100644 --- a/src/muz/base/bind_variables.cpp +++ b/src/muz/base/bind_variables.cpp @@ -64,7 +64,7 @@ expr_ref bind_variables::abstract(expr* term, cache_t& cache, unsigned scope) { } switch(e->get_kind()) { case AST_VAR: { - SASSERT(to_var(e)->get_idx() < scope); + // SASSERT(to_var(e)->get_idx() >= scope); // mixing bound variables and free is possible for the caller, // but not proper use. // So we assert here even though we don't check for it. diff --git a/src/muz/base/fp_params.pyg b/src/muz/base/fp_params.pyg index dea7ad328..8cee99540 100644 --- a/src/muz/base/fp_params.pyg +++ b/src/muz/base/fp_params.pyg @@ -83,9 +83,9 @@ def_module_params('fp', ('print_boogie_certificate', BOOL, False, 'print certificate for reachability or non-reachability using a ' + 'format understood by Boogie'), - ('print_statistics', BOOL, False, 'print statistics'), ('print_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), + ('print_statistics', BOOL, False, 'print statistics'), ('tab.selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('xform.bit_blast', BOOL, False, diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 6fa4b39c4..231dca0d3 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -355,7 +355,7 @@ private: } void print_statistics(cmd_context& ctx) { - if (m_dl_ctx->get_params().print_statistics()) { + if (ctx.params().m_statistics) { statistics st; datalog::context& dlctx = m_dl_ctx->dlctx(); dlctx.collect_statistics(st); diff --git a/src/muz/spacer/spacer_context.cpp b/src/muz/spacer/spacer_context.cpp index 693812a31..f0e86f1a5 100644 --- a/src/muz/spacer/spacer_context.cpp +++ b/src/muz/spacer/spacer_context.cpp @@ -2683,7 +2683,7 @@ lbool context::solve(unsigned from_lvl) if (m_last_result == l_true) { m_stats.m_cex_depth = get_cex_depth (); } - + if (m_params.print_statistics ()) { statistics st; collect_statistics (st); @@ -3063,13 +3063,13 @@ lbool context::solve_core (unsigned from_lvl) IF_VERBOSE(1,verbose_stream() << "Entering level "<< lvl << "\n";); STRACE("spacer_progress", tout << "\n* LEVEL " << lvl << "\n";); - IF_VERBOSE(1, if (m_params.print_statistics ()) { statistics st; collect_statistics (st); }; ); + } // communicate failure to datalog::context if (m_context) { m_context->set_status(datalog::BOUNDED); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 8b7e2e63c..ff55598c2 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -483,6 +483,7 @@ public: s2g(m_solver, m_map, m_params, g, m_sat_mc); m_internalized_fmls.reset(); g.get_formulas(m_internalized_fmls); + TRACE("sat", m_solver.display(tout); tout << m_internalized_fmls << "\n";); m_internalized_converted = true; } @@ -529,7 +530,7 @@ private: throw default_exception("generation of proof objects is not supported in this mode"); } SASSERT(!g->proofs_enabled()); - TRACE("sat", g->display(tout);); + TRACE("sat", m_solver.display(tout); g->display(tout);); try { (*m_preprocess)(g, m_subgoals); } @@ -712,23 +713,35 @@ private: m_asms.reset(); unsigned j = 0; sat::literal lit; + sat::literal_set seen; for (unsigned i = 0; i < sz; ++i) { if (dep2asm.find(asms[i], lit)) { SASSERT(lit.var() <= m_solver.num_vars()); - m_asms.push_back(lit); - if (i != j && !m_weights.empty()) { - m_weights[j] = m_weights[i]; + if (!seen.contains(lit)) { + m_asms.push_back(lit); + seen.insert(lit); + if (i != j && !m_weights.empty()) { + m_weights[j] = m_weights[i]; + } + ++j; } - ++j; } } for (unsigned i = 0; i < get_num_assumptions(); ++i) { if (dep2asm.find(get_assumption(i), lit)) { SASSERT(lit.var() <= m_solver.num_vars()); - m_asms.push_back(lit); + if (!seen.contains(lit)) { + m_asms.push_back(lit); + seen.insert(lit); + } } } - + CTRACE("sat", dep2asm.size() != m_asms.size(), + tout << dep2asm.size() << " vs " << m_asms.size() << "\n"; + tout << m_asms << "\n"; + for (auto const& kv : dep2asm) { + tout << mk_pp(kv.m_key, m) << " " << kv.m_value << "\n"; + }); SASSERT(dep2asm.size() == m_asms.size()); } @@ -751,6 +764,7 @@ private: tout << mk_pp(kv.m_key, m) << " |-> " << mk_pp(kv.m_value, m) << "\n"; } tout << "core: "; for (auto c : core) tout << c << " "; tout << "\n"; + m_solver.display(tout); ); m_core.reset(); diff --git a/src/sat/tactic/goal2sat.cpp b/src/sat/tactic/goal2sat.cpp index 029ddf924..7faa89370 100644 --- a/src/sat/tactic/goal2sat.cpp +++ b/src/sat/tactic/goal2sat.cpp @@ -1167,7 +1167,7 @@ struct sat2goal::imp { } void operator()(sat::solver & s, atom2bool_var const & map, goal & r, ref & mc) { - if (s.inconsistent()) { + if (s.at_base_lvl() && s.inconsistent()) { r.assert_expr(m.mk_false()); return; } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index f6c809bb2..bb1c19b47 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -199,6 +199,7 @@ void parse_cmd_line_args(int argc, char ** argv) { } else if (strcmp(opt_name, "st") == 0) { g_display_statistics = true; + gparams::set("stats", "true"); } else if (strcmp(opt_name, "ist") == 0) { g_display_istatistics = true; From 8b4e1c120993d34357764e5e02145332a7078d7b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 Aug 2018 18:13:26 -0700 Subject: [PATCH 118/118] fix #1793 Signed-off-by: Nikolaj Bjorner --- src/api/api_numeral.cpp | 5 ++--- src/tactic/arith/card2bv_tactic.cpp | 6 +++--- src/util/mpq.cpp | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 2b77294d5..2891e8cc4 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -68,11 +68,10 @@ extern "C" { ('/' == *m) || ('-' == *m) || (' ' == *m) || ('\n' == *m) || ('.' == *m) || ('e' == *m) || - ('E' == *m) || + ('E' == *m) || ('+' == *m) || (is_float && (('p' == *m) || - ('P' == *m) || - ('+' == *m))))) { + ('P' == *m))))) { SET_ERROR_CODE(Z3_PARSER_ERROR, nullptr); RETURN_Z3(nullptr); } diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 97649cc2f..65b8d8bf3 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -80,10 +80,10 @@ public: } expr_ref_vector fmls(m); rw2.flush_side_constraints(fmls); - for (unsigned i = 0; !g->inconsistent() && i < fmls.size(); ++i) { - g->assert_expr(fmls[i].get()); + for (expr* e : fmls) { + g->assert_expr(e); } - + func_decl_ref_vector const& fns = rw2.fresh_constants(); if (!fns.empty()) { generic_model_converter* filter = alloc(generic_model_converter, m, "card2bv"); diff --git a/src/util/mpq.cpp b/src/util/mpq.cpp index 207614ee0..b126f4c5d 100644 --- a/src/util/mpq.cpp +++ b/src/util/mpq.cpp @@ -230,6 +230,10 @@ void mpq_manager::set(mpq & a, char const * val) { exp_sign = true; ++str; } + else if (str[0] == '+') { + exp_sign = false; + ++str; + } while (str[0]) { if ('0' <= str[0] && str[0] <= '9') { SASSERT(str[0] - '0' <= 9);